must add one to the extra_data size to transfer the 0 string terminator.
[Samba/gebeck_regimport.git] / source3 / smbd / quotas.c
blob39cb8f2432f858caad67f08860337bf42e1df9fe
1 /*
2 Unix SMB/CIFS implementation.
3 support for quotas
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 /*
23 * This is one of the most system dependent parts of Samba, and its
24 * done a litle differently. Each system has its own way of doing
25 * things :-(
28 #include "includes.h"
30 #if defined(VXFS_QUOTA)
33 * In addition to their native filesystems, some systems have Veritas VxFS.
34 * Declare here, define at end: reduces likely "include" interaction problems.
35 * David Lee <T.D.Lee@durham.ac.uk>
37 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
39 #endif /* VXFS_QUOTA */
41 #ifdef LINUX
43 #include <sys/types.h>
44 #include <asm/types.h>
47 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
48 * Unfortunately, RH7.1 ships with a different quota system using struct mem_dqblk
49 * rather than the struct dqblk defined in /usr/include/sys/quota.h.
50 * This means we must include linux/quota.h to have a hope of working on
51 * RH7.1 systems. And it also means this breaks if the kernel is upgraded
52 * to a Linus 2.4.x (where x > the minor number shipped with RH7.1) until
53 * Linus synchronises with the AC patches. Sometimes I *hate* Linux :-). JRA.
56 #include <linux/quota.h>
57 #ifdef HAVE_LINUX_XQM_H
58 #include <linux/xqm.h>
59 #endif
61 #include <mntent.h>
62 #include <linux/unistd.h>
65 #define LINUX_QUOTAS_2
67 typedef struct _LINUX_SMB_DISK_QUOTA {
68 SMB_BIG_UINT bsize;
69 SMB_BIG_UINT hardlimit; /* In bsize units. */
70 SMB_BIG_UINT softlimit; /* In bsize units. */
71 SMB_BIG_UINT curblocks; /* In bsize units. */
72 SMB_BIG_UINT ihardlimit; /* inode hard limit. */
73 SMB_BIG_UINT isoftlimit; /* inode soft limit. */
74 SMB_BIG_UINT curinodes; /* Current used inodes. */
75 } LINUX_SMB_DISK_QUOTA;
77 /****************************************************************************
78 Abstract out the XFS Quota Manager quota get call.
79 ****************************************************************************/
81 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
83 int ret = -1;
84 #ifdef HAVE_LINUX_XQM_H
85 struct fs_disk_quota D;
86 ZERO_STRUCT(D);
88 if ((ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
89 return ret;
91 dp->bsize = (SMB_BIG_UINT)512;
92 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
93 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
94 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
95 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
96 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
97 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
98 #endif
99 return ret;
102 /****************************************************************************
103 Abstract out the old and new Linux quota get calls.
104 ****************************************************************************/
106 static int get_smb_linux_vfs_quota(char *path, uid_t euser_id, LINUX_SMB_DISK_QUOTA *dp)
108 int ret;
109 #ifdef LINUX_QUOTAS_1
110 struct dqblk D;
111 ZERO_STRUCT(D);
112 dp->bsize = (SMB_BIG_UINT)1024;
113 #else /* LINUX_QUOTAS_2 */
114 struct mem_dqblk D;
115 ZERO_STRUCT(D);
116 #ifndef QUOTABLOCK_SIZE
117 #define QUOTABLOCK_SIZE 1024
118 #endif
119 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
120 #endif
122 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D)))
123 return -1;
125 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
126 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
127 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
128 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
129 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
131 #ifdef LINUX_QUOTAS_1
132 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
133 #else /* LINUX_QUOTAS_2 */
134 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace)/ dp->bsize;
135 #endif
137 return 0;
140 /****************************************************************************
141 try to get the disk space from disk quotas (LINUX version)
142 ****************************************************************************/
144 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
146 int r;
147 SMB_STRUCT_STAT S;
148 FILE *fp;
149 LINUX_SMB_DISK_QUOTA D;
150 struct mntent *mnt;
151 SMB_DEV_T devno;
152 int found;
153 uid_t euser_id;
155 euser_id = geteuid();
157 /* find the block device file */
159 if ( sys_stat(path, &S) == -1 )
160 return(False) ;
162 devno = S.st_dev ;
164 fp = setmntent(MOUNTED,"r");
165 found = False ;
167 while ((mnt = getmntent(fp))) {
168 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
169 continue ;
171 if (S.st_dev == devno) {
172 found = True ;
173 break;
177 endmntent(fp) ;
179 if (!found)
180 return(False);
182 save_re_uid();
183 set_effective_uid(0);
184 if (strcmp(mnt->mnt_type, "xfs") == 0)
185 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, &D);
186 else
187 r=get_smb_linux_vfs_quota(mnt->mnt_fsname, euser_id, &D);
188 restore_re_uid();
190 /* Use softlimit to determine disk space, except when it has been exceeded */
191 *bsize = D.bsize;
192 if (r == -1) {
193 if (errno == EDQUOT) {
194 *dfree =0;
195 *dsize =D.curblocks;
196 return (True);
197 } else {
198 return(False);
202 /* Use softlimit to determine disk space, except when it has been exceeded */
203 if (
204 (D.softlimit && D.curblocks >= D.softlimit) ||
205 (D.hardlimit && D.curblocks >= D.hardlimit) ||
206 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
207 (D.ihardlimit && D.curinodes>=D.ihardlimit)
209 *dfree = 0;
210 *dsize = D.curblocks;
211 } else if (D.softlimit==0 && D.hardlimit==0) {
212 return(False);
213 } else {
214 if (D.softlimit == 0)
215 D.softlimit = D.hardlimit;
216 *dfree = D.softlimit - D.curblocks;
217 *dsize = D.softlimit;
220 return (True);
223 #elif defined(CRAY)
225 #include <sys/quota.h>
226 #include <mntent.h>
228 /****************************************************************************
229 try to get the disk space from disk quotas (CRAY VERSION)
230 ****************************************************************************/
232 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
234 struct mntent *mnt;
235 FILE *fd;
236 SMB_STRUCT_STAT sbuf;
237 SMB_DEV_T devno ;
238 static SMB_DEV_T devno_cached = 0 ;
239 static pstring name;
240 struct q_request request ;
241 struct qf_header header ;
242 static int quota_default = 0 ;
243 int found ;
245 if ( sys_stat(path,&sbuf) == -1 )
246 return(False) ;
248 devno = sbuf.st_dev ;
250 if ( devno != devno_cached ) {
252 devno_cached = devno ;
254 if ((fd = setmntent(KMTAB)) == NULL)
255 return(False) ;
257 found = False ;
259 while ((mnt = getmntent(fd)) != NULL) {
261 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
262 continue ;
264 if (sbuf.st_dev == devno) {
266 found = True ;
267 break ;
273 pstrcpy(name,mnt->mnt_dir) ;
274 endmntent(fd) ;
276 if ( ! found )
277 return(False) ;
280 request.qf_magic = QF_MAGIC ;
281 request.qf_entry.id = geteuid() ;
283 if (quotactl(name, Q_GETQUOTA, &request) == -1)
284 return(False) ;
286 if ( ! request.user )
287 return(False) ;
289 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
291 if ( ! quota_default ) {
293 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
294 return(False) ;
295 else
296 quota_default = header.user_h.def_fq ;
299 *dfree = quota_default ;
301 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
303 *dfree = 0 ;
305 }else{
307 *dfree = request.qf_entry.user_q.f_quota ;
311 *dsize = request.qf_entry.user_q.f_use ;
313 if ( *dfree < *dsize )
314 *dfree = 0 ;
315 else
316 *dfree -= *dsize ;
318 *bsize = 4096 ; /* Cray blocksize */
320 return(True) ;
325 #elif defined(SUNOS5) || defined(SUNOS4)
327 #include <fcntl.h>
328 #include <sys/param.h>
329 #if defined(SUNOS5)
330 #include <sys/fs/ufs_quota.h>
331 #include <sys/mnttab.h>
332 #include <sys/mntent.h>
333 #else /* defined(SUNOS4) */
334 #include <ufs/quota.h>
335 #include <mntent.h>
336 #endif
338 #if defined(SUNOS5)
340 /****************************************************************************
341 Allows querying of remote hosts for quotas on NFS mounted shares.
342 Supports normal NFS and AMD mounts.
343 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
344 ****************************************************************************/
346 #include <rpc/rpc.h>
347 #include <rpc/types.h>
348 #include <rpcsvc/rquota.h>
349 #include <rpc/nettype.h>
350 #include <rpc/xdr.h>
352 static int quotastat;
354 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
356 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
357 return(0);
358 if (!xdr_int(xdrsp, &args->gqa_uid))
359 return(0);
360 return (1);
363 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
365 if (!xdr_int(xdrsp, &quotastat)) {
366 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
367 return 0;
369 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
370 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
371 return 0;
373 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
374 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
375 return 0;
377 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
378 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
379 return 0;
381 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
382 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
383 return 0;
385 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
386 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
387 return 0;
389 return (1);
392 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
393 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
395 uid_t uid = euser_id;
396 struct dqblk D;
397 char *mnttype = nfspath;
398 CLIENT *clnt;
399 struct getquota_rslt gqr;
400 struct getquota_args args;
401 char *cutstr, *pathname, *host, *testpath;
402 int len;
403 static struct timeval timeout = {2,0};
404 enum clnt_stat clnt_stat;
405 BOOL ret = True;
407 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
409 len=strcspn(mnttype, ":");
410 pathname=strstr(mnttype, ":");
411 cutstr = (char *) malloc(sizeof(char) * len );
412 if (!cutstr)
413 return False;
415 host = strncat(cutstr,mnttype, sizeof(char) * len );
416 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
417 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
418 testpath=strchr_m(mnttype, ':');
419 args.gqa_pathp = testpath+1;
420 args.gqa_uid = uid;
422 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
424 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
425 ret = False;
426 goto out;
429 clnt->cl_auth = authunix_create_default();
430 DEBUG(9,("nfs_quotas: auth_success\n"));
432 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
434 if (clnt_stat != RPC_SUCCESS) {
435 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
436 ret = False;
437 goto out;
441 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
442 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
443 * something sensible.
446 switch ( quotastat ) {
447 case 0:
448 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
449 ret = False;
450 goto out;
452 case 1:
453 DEBUG(9,("nfs_quotas: Good quota data\n"));
454 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
455 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
456 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
457 break;
459 case 2:
460 case 3:
461 D.dqb_bsoftlimit = 1;
462 D.dqb_curblocks = 1;
463 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
464 break;
466 default:
467 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
468 break;
471 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",
472 quotastat,
473 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
474 gqr.getquota_rslt_u.gqr_rquota.rq_active,
475 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
476 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
477 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
479 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
480 *dsize = D.dqb_bsoftlimit;
482 if (D.dqb_curblocks == D.dqb_curblocks == 1)
483 *bsize = 512;
485 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
486 *dfree = 0;
487 *dsize = D.dqb_curblocks;
488 } else
489 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
491 out:
493 if (clnt) {
494 if (clnt->cl_auth)
495 auth_destroy(clnt->cl_auth);
496 clnt_destroy(clnt);
499 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
501 SAFE_FREE(cutstr);
502 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
503 return ret;
505 #endif
507 /****************************************************************************
508 try to get the disk space from disk quotas (SunOS & Solaris2 version)
509 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
510 ****************************************************************************/
512 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
514 uid_t euser_id;
515 int ret;
516 struct dqblk D;
517 #if defined(SUNOS5)
518 struct quotctl command;
519 int file;
520 static struct mnttab mnt;
521 static pstring name;
522 pstring devopt;
523 #else /* SunOS4 */
524 struct mntent *mnt;
525 static pstring name;
526 #endif
527 FILE *fd;
528 SMB_STRUCT_STAT sbuf;
529 SMB_DEV_T devno ;
530 static SMB_DEV_T devno_cached = 0 ;
531 static int found ;
533 euser_id = geteuid();
535 if ( sys_stat(path,&sbuf) == -1 )
536 return(False) ;
538 devno = sbuf.st_dev ;
539 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
540 if ( devno != devno_cached ) {
541 devno_cached = devno ;
542 #if defined(SUNOS5)
543 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
544 return(False) ;
546 found = False ;
547 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
548 while (getmntent(fd, &mnt) == 0) {
549 if( !hasmntopt(&mnt, devopt) )
550 continue;
552 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
554 /* quotas are only on vxfs, UFS or NFS */
555 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
556 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
557 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
558 found = True ;
559 break;
563 pstrcpy(name,mnt.mnt_mountp) ;
564 pstrcat(name,"/quotas") ;
565 fclose(fd) ;
566 #else /* SunOS4 */
567 if ((fd = setmntent(MOUNTED, "r")) == NULL)
568 return(False) ;
570 found = False ;
571 while ((mnt = getmntent(fd)) != NULL) {
572 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
573 continue ;
574 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
575 if (sbuf.st_dev == devno) {
576 found = True ;
577 break;
581 pstrcpy(name,mnt->mnt_fsname) ;
582 endmntent(fd) ;
583 #endif
586 if ( ! found )
587 return(False) ;
589 save_re_uid();
590 set_effective_uid(0);
592 #if defined(SUNOS5)
593 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
594 BOOL retval;
595 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
596 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
597 restore_re_uid();
598 return retval;
601 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
602 if((file=sys_open(name, O_RDONLY,0))<0) {
603 restore_re_uid();
604 return(False);
606 command.op = Q_GETQUOTA;
607 command.uid = euser_id;
608 command.addr = (caddr_t) &D;
609 ret = ioctl(file, Q_QUOTACTL, &command);
610 close(file);
611 #else
612 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
613 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
614 #endif
616 restore_re_uid();
618 if (ret < 0) {
619 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
621 #if defined(SUNOS5) && defined(VXFS_QUOTA)
622 /* If normal quotactl() fails, try vxfs private calls */
623 set_effective_uid(euser_id);
624 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
625 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
626 BOOL retval;
627 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
628 return(retval);
630 #else
631 return(False);
632 #endif
635 /* If softlimit is zero, set it equal to hardlimit.
638 if (D.dqb_bsoftlimit==0)
639 D.dqb_bsoftlimit = D.dqb_bhardlimit;
641 /* Use softlimit to determine disk space. A user exceeding the quota is told
642 * that there's no space left. Writes might actually work for a bit if the
643 * hardlimit is set higher than softlimit. Effectively the disk becomes
644 * made of rubber latex and begins to expand to accommodate the user :-)
647 if (D.dqb_bsoftlimit==0)
648 return(False);
649 *bsize = DEV_BSIZE;
650 *dsize = D.dqb_bsoftlimit;
652 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
653 *dfree = 0;
654 *dsize = D.dqb_curblocks;
655 } else
656 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
658 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
659 path,(double)*bsize,(double)*dfree,(double)*dsize));
661 return(True);
665 #elif defined(OSF1)
666 #include <ufs/quota.h>
668 /****************************************************************************
669 try to get the disk space from disk quotas - OSF1 version
670 ****************************************************************************/
672 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
674 int r, save_errno;
675 struct dqblk D;
676 SMB_STRUCT_STAT S;
677 uid_t euser_id;
680 * This code presumes that OSF1 will only
681 * give out quota info when the real uid
682 * matches the effective uid. JRA.
684 euser_id = geteuid();
685 save_re_uid();
686 if (set_re_uid() != 0) return False;
688 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
689 if (r) {
690 save_errno = errno;
693 restore_re_uid();
695 *bsize = DEV_BSIZE;
697 if (r)
699 if (save_errno == EDQUOT) /* disk quota exceeded */
701 *dfree = 0;
702 *dsize = D.dqb_curblocks;
703 return (True);
705 else
706 return (False);
709 /* If softlimit is zero, set it equal to hardlimit.
712 if (D.dqb_bsoftlimit==0)
713 D.dqb_bsoftlimit = D.dqb_bhardlimit;
715 /* Use softlimit to determine disk space, except when it has been exceeded */
717 if (D.dqb_bsoftlimit==0)
718 return(False);
720 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
721 *dfree = 0;
722 *dsize = D.dqb_curblocks;
723 } else {
724 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
725 *dsize = D.dqb_bsoftlimit;
727 return (True);
730 #elif defined (IRIX6)
731 /****************************************************************************
732 try to get the disk space from disk quotas (IRIX 6.2 version)
733 ****************************************************************************/
735 #include <sys/quota.h>
736 #include <mntent.h>
738 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
740 uid_t euser_id;
741 int r;
742 struct dqblk D;
743 struct fs_disk_quota F;
744 SMB_STRUCT_STAT S;
745 FILE *fp;
746 struct mntent *mnt;
747 SMB_DEV_T devno;
748 int found;
750 /* find the block device file */
752 if ( sys_stat(path, &S) == -1 ) {
753 return(False) ;
756 devno = S.st_dev ;
758 fp = setmntent(MOUNTED,"r");
759 found = False ;
761 while ((mnt = getmntent(fp))) {
762 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
763 continue ;
764 if (S.st_dev == devno) {
765 found = True ;
766 break ;
769 endmntent(fp) ;
771 if (!found) {
772 return(False);
775 euser_id=geteuid();
776 save_re_uid();
777 set_effective_uid(0);
779 /* Use softlimit to determine disk space, except when it has been exceeded */
781 *bsize = 512;
783 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
785 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
787 restore_re_uid();
789 if (r==-1)
790 return(False);
792 /* Use softlimit to determine disk space, except when it has been exceeded */
793 if (
794 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
795 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
796 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
797 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
800 *dfree = 0;
801 *dsize = D.dqb_curblocks;
803 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
805 return(False);
807 else
809 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
810 *dsize = D.dqb_bsoftlimit;
814 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
816 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
818 restore_re_uid();
820 if (r==-1)
821 return(False);
823 /* Use softlimit to determine disk space, except when it has been exceeded */
824 if (
825 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
826 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
827 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
828 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
831 *dfree = 0;
832 *dsize = F.d_bcount;
834 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
836 return(False);
838 else
840 *dfree = (F.d_blk_softlimit - F.d_bcount);
841 *dsize = F.d_blk_softlimit;
845 else
847 restore_re_uid();
848 return(False);
851 return (True);
855 #else
857 #if defined(__FreeBSD__) || defined(__OpenBSD__)
858 #include <ufs/ufs/quota.h>
859 #include <machine/param.h>
860 #elif AIX
861 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
862 #include <jfs/quota.h>
863 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
864 #define dqb_curfiles dqb_curinodes
865 #define dqb_fhardlimit dqb_ihardlimit
866 #define dqb_fsoftlimit dqb_isoftlimit
867 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
868 #include <sys/quota.h>
869 #include <devnm.h>
870 #endif
872 /****************************************************************************
873 try to get the disk space from disk quotas - default version
874 ****************************************************************************/
876 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
878 int r;
879 struct dqblk D;
880 uid_t euser_id;
881 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
882 char dev_disk[256];
883 SMB_STRUCT_STAT S;
884 /* find the block device file */
885 if ((sys_stat(path, &S)<0) ||
886 (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0)) return (False);
887 #endif
889 euser_id = geteuid();
891 #ifdef HPUX
892 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
893 save_re_uid();
894 if (set_re_uid() != 0) return False;
896 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
898 restore_re_uid();
899 #else
900 #if defined(__FreeBSD__) || defined(__OpenBSD__)
902 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
903 gid_t egrp_id;
905 save_re_uid();
906 set_effective_uid(0);
908 egrp_id = getegid();
909 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
911 /* As FreeBSD has group quotas, if getting the user
912 quota fails, try getting the group instead. */
913 if (r) {
914 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
917 restore_re_uid();
919 #elif defined(AIX)
920 /* AIX has both USER and GROUP quotas:
921 Get the USER quota (ohnielse@fysik.dtu.dk) */
922 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
923 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
924 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
925 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
926 #endif /* HPUX */
928 /* Use softlimit to determine disk space, except when it has been exceeded */
929 #if defined(__FreeBSD__) || defined(__OpenBSD__)
930 *bsize = DEV_BSIZE;
931 #else /* !__FreeBSD__ && !__OpenBSD__ */
932 *bsize = 1024;
933 #endif /*!__FreeBSD__ && !__OpenBSD__ */
935 if (r)
937 if (errno == EDQUOT)
939 *dfree =0;
940 *dsize =D.dqb_curblocks;
941 return (True);
943 else return(False);
946 /* If softlimit is zero, set it equal to hardlimit.
949 if (D.dqb_bsoftlimit==0)
950 D.dqb_bsoftlimit = D.dqb_bhardlimit;
952 if (D.dqb_bsoftlimit==0)
953 return(False);
954 /* Use softlimit to determine disk space, except when it has been exceeded */
955 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
956 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
957 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
958 #endif
960 *dfree = 0;
961 *dsize = D.dqb_curblocks;
963 else {
964 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
965 *dsize = D.dqb_bsoftlimit;
967 return (True);
970 #endif
972 #if defined(VXFS_QUOTA)
974 /****************************************************************************
975 Try to get the disk space from Veritas disk quotas.
976 David Lee <T.D.Lee@durham.ac.uk> August 1999.
978 Background assumptions:
979 Potentially under many Operating Systems. Initially Solaris 2.
981 My guess is that Veritas is largely, though not entirely,
982 independent of OS. So I have separated it out.
984 There may be some details. For example, OS-specific "include" files.
986 It is understood that HPUX 10 somehow gets Veritas quotas without
987 any special effort; if so, this routine need not be compiled in.
988 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
990 Warning:
991 It is understood that Veritas do not publicly support this ioctl interface.
992 Rather their preference would be for the user (us) to call the native
993 OS and then for the OS itself to call through to the VxFS filesystem.
994 Presumably HPUX 10, see above, does this.
996 Hints for porting:
997 Add your OS to "IFLIST" below.
998 Get it to compile successfully:
999 Almost certainly "include"s require attention: see SUNOS5.
1000 In the main code above, arrange for it to be called: see SUNOS5.
1001 Test!
1003 ****************************************************************************/
1005 /* "IFLIST"
1006 * This "if" is a list of ports:
1007 * if defined(OS1) || defined(OS2) || ...
1009 #if defined(SUNOS5)
1011 #if defined(SUNOS5)
1012 #include <sys/fs/vx_solaris.h>
1013 #endif
1014 #include <sys/fs/vx_machdep.h>
1015 #include <sys/fs/vx_layout.h>
1016 #include <sys/fs/vx_quota.h>
1017 #include <sys/fs/vx_aioctl.h>
1018 #include <sys/fs/vx_ioctl.h>
1020 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1022 uid_t user_id, euser_id;
1023 int ret;
1024 struct vx_dqblk D;
1025 struct vx_quotctl quotabuf;
1026 struct vx_genioctl genbuf;
1027 pstring qfname;
1028 int file;
1031 * "name" may or may not include a trailing "/quotas".
1032 * Arranging consistency of calling here in "quotas.c" may not be easy and
1033 * it might be easier to examine and adjust it here.
1034 * Fortunately, VxFS seems not to mind at present.
1036 pstrcpy(qfname, name) ;
1037 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1039 euser_id = geteuid();
1040 set_effective_uid(0);
1042 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1043 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1044 set_effective_uid(euser_id);
1045 return(False);
1047 genbuf.ioc_cmd = VX_QUOTACTL;
1048 genbuf.ioc_up = (void *) &quotabuf;
1050 quotabuf.cmd = VX_GETQUOTA;
1051 quotabuf.uid = euser_id;
1052 quotabuf.addr = (caddr_t) &D;
1053 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1054 close(file);
1056 set_effective_uid(euser_id);
1058 if (ret < 0) {
1059 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1060 return(False);
1063 /* If softlimit is zero, set it equal to hardlimit.
1066 if (D.dqb_bsoftlimit==0)
1067 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1069 /* Use softlimit to determine disk space. A user exceeding the quota is told
1070 * that there's no space left. Writes might actually work for a bit if the
1071 * hardlimit is set higher than softlimit. Effectively the disk becomes
1072 * made of rubber latex and begins to expand to accommodate the user :-)
1074 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1075 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1076 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1078 if (D.dqb_bsoftlimit==0)
1079 return(False);
1080 *bsize = DEV_BSIZE;
1081 *dsize = D.dqb_bsoftlimit;
1083 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1084 *dfree = 0;
1085 *dsize = D.dqb_curblocks;
1086 } else
1087 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1089 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1090 path,(double)*bsize,(double)*dfree,(double)*dsize));
1092 return(True);
1095 #endif /* SUNOS5 || ... */
1097 #endif /* VXFS_QUOTA */