Make sure we don't clobber the stack when response consists of the empty
[Samba/gebeck_regimport.git] / source3 / smbd / quotas.c
blobc0b2db61730d7819b9ba519a44a2a458d4dfe9dd
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 #undef DBGC_CLASS
31 #define DBGC_CLASS DBGC_QUOTA
33 #ifndef HAVE_SYS_QUOTAS
35 /* just a quick hack because sysquotas.h is included before linux/quota.h */
36 #ifdef QUOTABLOCK_SIZE
37 #undef QUOTABLOCK_SIZE
38 #endif
40 #ifdef WITH_QUOTAS
42 #if defined(VXFS_QUOTA)
45 * In addition to their native filesystems, some systems have Veritas VxFS.
46 * Declare here, define at end: reduces likely "include" interaction problems.
47 * David Lee <T.D.Lee@durham.ac.uk>
49 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
51 #endif /* VXFS_QUOTA */
53 #ifdef LINUX
55 #include <sys/types.h>
56 #include <mntent.h>
59 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
60 * So we include all the files has *should* be in the system into a large,
61 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
64 #include "samba_linux_quota.h"
65 #include "samba_xfs_quota.h"
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, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
83 struct fs_disk_quota D;
84 int ret;
86 ZERO_STRUCT(D);
88 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
90 if (ret)
91 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
93 if (ret)
94 return ret;
96 dp->bsize = (SMB_BIG_UINT)512;
97 dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
98 dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
99 dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
100 dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
101 dp->curinodes = (SMB_BIG_UINT)D.d_icount;
102 dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
104 return ret;
107 /****************************************************************************
108 Abstract out the old and new Linux quota get calls.
109 ****************************************************************************/
111 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
113 struct v1_kern_dqblk D;
114 int ret;
116 ZERO_STRUCT(D);
118 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
120 if (ret && errno != EDQUOT)
121 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
123 if (ret && errno != EDQUOT)
124 return ret;
126 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
127 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
128 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
129 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
130 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
131 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
132 dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
134 return ret;
137 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
139 struct v2_kern_dqblk D;
140 int ret;
142 ZERO_STRUCT(D);
144 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
146 if (ret && errno != EDQUOT)
147 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
149 if (ret && errno != EDQUOT)
150 return ret;
152 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
153 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
154 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
155 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
156 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
157 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
158 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
160 return ret;
163 /****************************************************************************
164 Brand-new generic quota interface.
165 ****************************************************************************/
167 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
169 struct if_dqblk D;
170 int ret;
172 ZERO_STRUCT(D);
174 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
176 if (ret && errno != EDQUOT)
177 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
179 if (ret && errno != EDQUOT)
180 return ret;
182 dp->bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
183 dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
184 dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
185 dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
186 dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
187 dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
188 dp->curblocks = ((SMB_BIG_UINT)D.dqb_curspace) / dp->bsize;
190 return ret;
193 /****************************************************************************
194 Try to get the disk space from disk quotas (LINUX version).
195 ****************************************************************************/
197 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
199 int r;
200 SMB_STRUCT_STAT S;
201 FILE *fp;
202 LINUX_SMB_DISK_QUOTA D;
203 struct mntent *mnt;
204 SMB_DEV_T devno;
205 int found;
206 uid_t euser_id;
207 gid_t egrp_id;
209 euser_id = geteuid();
210 egrp_id = getegid();
212 /* find the block device file */
214 if ( sys_stat(path, &S) == -1 )
215 return(False) ;
217 devno = S.st_dev ;
219 fp = setmntent(MOUNTED,"r");
220 found = False ;
222 while ((mnt = getmntent(fp))) {
223 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
224 continue ;
226 if (S.st_dev == devno) {
227 found = True ;
228 break;
232 endmntent(fp) ;
234 if (!found)
235 return(False);
237 save_re_uid();
238 set_effective_uid(0);
240 if (strcmp(mnt->mnt_type, "xfs")==0) {
241 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
242 } else {
243 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
244 if (r == -1 && errno != EDQUOT) {
245 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
246 if (r == -1 && errno != EDQUOT)
247 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
251 restore_re_uid();
253 /* Use softlimit to determine disk space, except when it has been exceeded */
254 *bsize = D.bsize;
255 if (r == -1) {
256 if (errno == EDQUOT) {
257 *dfree =0;
258 *dsize =D.curblocks;
259 return (True);
260 } else {
261 return(False);
265 /* Use softlimit to determine disk space, except when it has been exceeded */
266 if (
267 (D.softlimit && D.curblocks >= D.softlimit) ||
268 (D.hardlimit && D.curblocks >= D.hardlimit) ||
269 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
270 (D.ihardlimit && D.curinodes>=D.ihardlimit)
272 *dfree = 0;
273 *dsize = D.curblocks;
274 } else if (D.softlimit==0 && D.hardlimit==0) {
275 return(False);
276 } else {
277 if (D.softlimit == 0)
278 D.softlimit = D.hardlimit;
279 *dfree = D.softlimit - D.curblocks;
280 *dsize = D.softlimit;
283 return (True);
286 #elif defined(CRAY)
288 #include <sys/quota.h>
289 #include <mntent.h>
291 /****************************************************************************
292 try to get the disk space from disk quotas (CRAY VERSION)
293 ****************************************************************************/
295 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
297 struct mntent *mnt;
298 FILE *fd;
299 SMB_STRUCT_STAT sbuf;
300 SMB_DEV_T devno ;
301 static SMB_DEV_T devno_cached = 0 ;
302 static pstring name;
303 struct q_request request ;
304 struct qf_header header ;
305 static int quota_default = 0 ;
306 int found ;
308 if ( sys_stat(path,&sbuf) == -1 )
309 return(False) ;
311 devno = sbuf.st_dev ;
313 if ( devno != devno_cached ) {
315 devno_cached = devno ;
317 if ((fd = setmntent(KMTAB)) == NULL)
318 return(False) ;
320 found = False ;
322 while ((mnt = getmntent(fd)) != NULL) {
324 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
325 continue ;
327 if (sbuf.st_dev == devno) {
329 found = True ;
330 break ;
336 pstrcpy(name,mnt->mnt_dir) ;
337 endmntent(fd) ;
339 if ( ! found )
340 return(False) ;
343 request.qf_magic = QF_MAGIC ;
344 request.qf_entry.id = geteuid() ;
346 if (quotactl(name, Q_GETQUOTA, &request) == -1)
347 return(False) ;
349 if ( ! request.user )
350 return(False) ;
352 if ( request.qf_entry.user_q.f_quota == QFV_DEFAULT ) {
354 if ( ! quota_default ) {
356 if ( quotactl(name, Q_GETHEADER, &header) == -1 )
357 return(False) ;
358 else
359 quota_default = header.user_h.def_fq ;
362 *dfree = quota_default ;
364 }else if ( request.qf_entry.user_q.f_quota == QFV_PREVENT ) {
366 *dfree = 0 ;
368 }else{
370 *dfree = request.qf_entry.user_q.f_quota ;
374 *dsize = request.qf_entry.user_q.f_use ;
376 if ( *dfree < *dsize )
377 *dfree = 0 ;
378 else
379 *dfree -= *dsize ;
381 *bsize = 4096 ; /* Cray blocksize */
383 return(True) ;
388 #elif defined(SUNOS5) || defined(SUNOS4)
390 #include <fcntl.h>
391 #include <sys/param.h>
392 #if defined(SUNOS5)
393 #include <sys/fs/ufs_quota.h>
394 #include <sys/mnttab.h>
395 #include <sys/mntent.h>
396 #else /* defined(SUNOS4) */
397 #include <ufs/quota.h>
398 #include <mntent.h>
399 #endif
401 #if defined(SUNOS5)
403 /****************************************************************************
404 Allows querying of remote hosts for quotas on NFS mounted shares.
405 Supports normal NFS and AMD mounts.
406 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
407 ****************************************************************************/
409 #include <rpc/rpc.h>
410 #include <rpc/types.h>
411 #include <rpcsvc/rquota.h>
412 #include <rpc/nettype.h>
413 #include <rpc/xdr.h>
415 static int quotastat;
417 static int xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
419 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
420 return(0);
421 if (!xdr_int(xdrsp, &args->gqa_uid))
422 return(0);
423 return (1);
426 static int xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
428 if (!xdr_int(xdrsp, &quotastat)) {
429 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
430 return 0;
432 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
433 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
434 return 0;
436 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
437 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
438 return 0;
440 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
441 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
442 return 0;
444 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
445 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
446 return 0;
448 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
449 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
450 return 0;
452 return (1);
455 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
456 static BOOL nfs_quotas(char *nfspath, uid_t euser_id, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
458 uid_t uid = euser_id;
459 struct dqblk D;
460 char *mnttype = nfspath;
461 CLIENT *clnt;
462 struct getquota_rslt gqr;
463 struct getquota_args args;
464 char *cutstr, *pathname, *host, *testpath;
465 int len;
466 static struct timeval timeout = {2,0};
467 enum clnt_stat clnt_stat;
468 BOOL ret = True;
470 *bsize = *dfree = *dsize = (SMB_BIG_UINT)0;
472 len=strcspn(mnttype, ":");
473 pathname=strstr(mnttype, ":");
474 cutstr = (char *) malloc(len+1);
475 if (!cutstr)
476 return False;
478 memset(cutstr, '\0', len+1);
479 host = strncat(cutstr,mnttype, sizeof(char) * len );
480 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
481 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
482 testpath=strchr_m(mnttype, ':');
483 args.gqa_pathp = testpath+1;
484 args.gqa_uid = uid;
486 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
488 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
489 ret = False;
490 goto out;
493 clnt->cl_auth = authunix_create_default();
494 DEBUG(9,("nfs_quotas: auth_success\n"));
496 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
498 if (clnt_stat != RPC_SUCCESS) {
499 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
500 ret = False;
501 goto out;
505 * quotastat returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
506 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
507 * something sensible.
510 switch ( quotastat ) {
511 case 0:
512 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", quotastat ));
513 ret = False;
514 goto out;
516 case 1:
517 DEBUG(9,("nfs_quotas: Good quota data\n"));
518 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
519 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
520 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
521 break;
523 case 2:
524 case 3:
525 D.dqb_bsoftlimit = 1;
526 D.dqb_curblocks = 1;
527 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", quotastat ));
528 break;
530 default:
531 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", quotastat ));
532 break;
535 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",
536 quotastat,
537 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
538 gqr.getquota_rslt_u.gqr_rquota.rq_active,
539 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
540 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
541 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
543 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
544 *dsize = D.dqb_bsoftlimit;
546 if (D.dqb_curblocks == D.dqb_curblocks == 1)
547 *bsize = 512;
549 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
550 *dfree = 0;
551 *dsize = D.dqb_curblocks;
552 } else
553 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
555 out:
557 if (clnt) {
558 if (clnt->cl_auth)
559 auth_destroy(clnt->cl_auth);
560 clnt_destroy(clnt);
563 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
565 SAFE_FREE(cutstr);
566 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
567 return ret;
569 #endif
571 /****************************************************************************
572 try to get the disk space from disk quotas (SunOS & Solaris2 version)
573 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
574 ****************************************************************************/
576 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
578 uid_t euser_id;
579 int ret;
580 struct dqblk D;
581 #if defined(SUNOS5)
582 struct quotctl command;
583 int file;
584 static struct mnttab mnt;
585 static pstring name;
586 pstring devopt;
587 #else /* SunOS4 */
588 struct mntent *mnt;
589 static pstring name;
590 #endif
591 FILE *fd;
592 SMB_STRUCT_STAT sbuf;
593 SMB_DEV_T devno ;
594 static SMB_DEV_T devno_cached = 0 ;
595 static int found ;
597 euser_id = geteuid();
599 if ( sys_stat(path,&sbuf) == -1 )
600 return(False) ;
602 devno = sbuf.st_dev ;
603 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
604 if ( devno != devno_cached ) {
605 devno_cached = devno ;
606 #if defined(SUNOS5)
607 if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
608 return(False) ;
610 found = False ;
611 slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
612 while (getmntent(fd, &mnt) == 0) {
613 if( !hasmntopt(&mnt, devopt) )
614 continue;
616 DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
618 /* quotas are only on vxfs, UFS or NFS */
619 if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
620 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
621 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
622 found = True ;
623 break;
627 pstrcpy(name,mnt.mnt_mountp) ;
628 pstrcat(name,"/quotas") ;
629 fclose(fd) ;
630 #else /* SunOS4 */
631 if ((fd = setmntent(MOUNTED, "r")) == NULL)
632 return(False) ;
634 found = False ;
635 while ((mnt = getmntent(fd)) != NULL) {
636 if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
637 continue ;
638 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
639 if (sbuf.st_dev == devno) {
640 found = True ;
641 break;
645 pstrcpy(name,mnt->mnt_fsname) ;
646 endmntent(fd) ;
647 #endif
650 if ( ! found )
651 return(False) ;
653 save_re_uid();
654 set_effective_uid(0);
656 #if defined(SUNOS5)
657 if ( strcmp( mnt.mnt_fstype, "nfs" ) == 0) {
658 BOOL retval;
659 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n", mnt.mnt_special));
660 retval = nfs_quotas(mnt.mnt_special, euser_id, bsize, dfree, dsize);
661 restore_re_uid();
662 return retval;
665 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
666 if((file=sys_open(name, O_RDONLY,0))<0) {
667 restore_re_uid();
668 return(False);
670 command.op = Q_GETQUOTA;
671 command.uid = euser_id;
672 command.addr = (caddr_t) &D;
673 ret = ioctl(file, Q_QUOTACTL, &command);
674 close(file);
675 #else
676 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
677 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
678 #endif
680 restore_re_uid();
682 if (ret < 0) {
683 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
685 #if defined(SUNOS5) && defined(VXFS_QUOTA)
686 /* If normal quotactl() fails, try vxfs private calls */
687 set_effective_uid(euser_id);
688 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
689 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
690 BOOL retval;
691 retval = disk_quotas_vxfs(name, path, bsize, dfree, dsize);
692 return(retval);
694 #else
695 return(False);
696 #endif
699 /* If softlimit is zero, set it equal to hardlimit.
702 if (D.dqb_bsoftlimit==0)
703 D.dqb_bsoftlimit = D.dqb_bhardlimit;
705 /* Use softlimit to determine disk space. A user exceeding the quota is told
706 * that there's no space left. Writes might actually work for a bit if the
707 * hardlimit is set higher than softlimit. Effectively the disk becomes
708 * made of rubber latex and begins to expand to accommodate the user :-)
711 if (D.dqb_bsoftlimit==0)
712 return(False);
713 *bsize = DEV_BSIZE;
714 *dsize = D.dqb_bsoftlimit;
716 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
717 *dfree = 0;
718 *dsize = D.dqb_curblocks;
719 } else
720 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
722 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
723 path,(double)*bsize,(double)*dfree,(double)*dsize));
725 return(True);
729 #elif defined(OSF1)
730 #include <ufs/quota.h>
732 /****************************************************************************
733 try to get the disk space from disk quotas - OSF1 version
734 ****************************************************************************/
736 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
738 int r, save_errno;
739 struct dqblk D;
740 SMB_STRUCT_STAT S;
741 uid_t euser_id;
744 * This code presumes that OSF1 will only
745 * give out quota info when the real uid
746 * matches the effective uid. JRA.
748 euser_id = geteuid();
749 save_re_uid();
750 if (set_re_uid() != 0) return False;
752 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
753 if (r) {
754 save_errno = errno;
757 restore_re_uid();
759 *bsize = DEV_BSIZE;
761 if (r)
763 if (save_errno == EDQUOT) /* disk quota exceeded */
765 *dfree = 0;
766 *dsize = D.dqb_curblocks;
767 return (True);
769 else
770 return (False);
773 /* If softlimit is zero, set it equal to hardlimit.
776 if (D.dqb_bsoftlimit==0)
777 D.dqb_bsoftlimit = D.dqb_bhardlimit;
779 /* Use softlimit to determine disk space, except when it has been exceeded */
781 if (D.dqb_bsoftlimit==0)
782 return(False);
784 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
785 *dfree = 0;
786 *dsize = D.dqb_curblocks;
787 } else {
788 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
789 *dsize = D.dqb_bsoftlimit;
791 return (True);
794 #elif defined (IRIX6)
795 /****************************************************************************
796 try to get the disk space from disk quotas (IRIX 6.2 version)
797 ****************************************************************************/
799 #include <sys/quota.h>
800 #include <mntent.h>
802 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
804 uid_t euser_id;
805 int r;
806 struct dqblk D;
807 struct fs_disk_quota F;
808 SMB_STRUCT_STAT S;
809 FILE *fp;
810 struct mntent *mnt;
811 SMB_DEV_T devno;
812 int found;
814 /* find the block device file */
816 if ( sys_stat(path, &S) == -1 ) {
817 return(False) ;
820 devno = S.st_dev ;
822 fp = setmntent(MOUNTED,"r");
823 found = False ;
825 while ((mnt = getmntent(fp))) {
826 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
827 continue ;
828 if (S.st_dev == devno) {
829 found = True ;
830 break ;
833 endmntent(fp) ;
835 if (!found) {
836 return(False);
839 euser_id=geteuid();
840 save_re_uid();
841 set_effective_uid(0);
843 /* Use softlimit to determine disk space, except when it has been exceeded */
845 *bsize = 512;
847 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
849 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
851 restore_re_uid();
853 if (r==-1)
854 return(False);
856 /* Use softlimit to determine disk space, except when it has been exceeded */
857 if (
858 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
859 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
860 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
861 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
864 *dfree = 0;
865 *dsize = D.dqb_curblocks;
867 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
869 return(False);
871 else
873 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
874 *dsize = D.dqb_bsoftlimit;
878 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
880 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
882 restore_re_uid();
884 if (r==-1)
885 return(False);
887 /* Use softlimit to determine disk space, except when it has been exceeded */
888 if (
889 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
890 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
891 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
892 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
895 *dfree = 0;
896 *dsize = F.d_bcount;
898 else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
900 return(False);
902 else
904 *dfree = (F.d_blk_softlimit - F.d_bcount);
905 *dsize = F.d_blk_softlimit;
909 else
911 restore_re_uid();
912 return(False);
915 return (True);
919 #else
921 #if defined(__FreeBSD__) || defined(__OpenBSD__)
922 #include <ufs/ufs/quota.h>
923 #include <machine/param.h>
924 #elif AIX
925 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
926 #include <jfs/quota.h>
927 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
928 #define dqb_curfiles dqb_curinodes
929 #define dqb_fhardlimit dqb_ihardlimit
930 #define dqb_fsoftlimit dqb_isoftlimit
931 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
932 #include <sys/quota.h>
933 #include <devnm.h>
934 #endif
936 /****************************************************************************
937 try to get the disk space from disk quotas - default version
938 ****************************************************************************/
940 BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
942 int r;
943 struct dqblk D;
944 uid_t euser_id;
945 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
946 char dev_disk[256];
947 SMB_STRUCT_STAT S;
949 /* find the block device file */
951 #ifdef HPUX
952 /* Need to set the cache flag to 1 for HPUX. Seems
953 * to have a significant performance boost when
954 * lstat calls on /dev access this function.
956 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 1)<0))
957 #else
958 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_dev, dev_disk, 256, 0)<0))
959 return (False);
960 #endif /* ifdef HPUX */
962 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) */
964 euser_id = geteuid();
966 #ifdef HPUX
967 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
968 save_re_uid();
969 if (set_re_uid() != 0) return False;
971 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
973 restore_re_uid();
974 #else
975 #if defined(__FreeBSD__) || defined(__OpenBSD__)
977 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
978 gid_t egrp_id;
980 save_re_uid();
981 set_effective_uid(0);
983 egrp_id = getegid();
984 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
986 /* As FreeBSD has group quotas, if getting the user
987 quota fails, try getting the group instead. */
988 if (r) {
989 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
992 restore_re_uid();
994 #elif defined(AIX)
995 /* AIX has both USER and GROUP quotas:
996 Get the USER quota (ohnielse@fysik.dtu.dk) */
997 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
998 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
999 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1000 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ */
1001 #endif /* HPUX */
1003 /* Use softlimit to determine disk space, except when it has been exceeded */
1004 #if defined(__FreeBSD__) || defined(__OpenBSD__)
1005 *bsize = DEV_BSIZE;
1006 #else /* !__FreeBSD__ && !__OpenBSD__ */
1007 *bsize = 1024;
1008 #endif /*!__FreeBSD__ && !__OpenBSD__ */
1010 if (r)
1012 if (errno == EDQUOT)
1014 *dfree =0;
1015 *dsize =D.dqb_curblocks;
1016 return (True);
1018 else return(False);
1021 /* If softlimit is zero, set it equal to hardlimit.
1024 if (D.dqb_bsoftlimit==0)
1025 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1027 if (D.dqb_bsoftlimit==0)
1028 return(False);
1029 /* Use softlimit to determine disk space, except when it has been exceeded */
1030 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1031 #if !defined(__FreeBSD__) && !defined(__OpenBSD__)
1032 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1033 #endif
1035 *dfree = 0;
1036 *dsize = D.dqb_curblocks;
1038 else {
1039 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1040 *dsize = D.dqb_bsoftlimit;
1042 return (True);
1045 #endif
1047 #if defined(VXFS_QUOTA)
1049 /****************************************************************************
1050 Try to get the disk space from Veritas disk quotas.
1051 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1053 Background assumptions:
1054 Potentially under many Operating Systems. Initially Solaris 2.
1056 My guess is that Veritas is largely, though not entirely,
1057 independent of OS. So I have separated it out.
1059 There may be some details. For example, OS-specific "include" files.
1061 It is understood that HPUX 10 somehow gets Veritas quotas without
1062 any special effort; if so, this routine need not be compiled in.
1063 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1065 Warning:
1066 It is understood that Veritas do not publicly support this ioctl interface.
1067 Rather their preference would be for the user (us) to call the native
1068 OS and then for the OS itself to call through to the VxFS filesystem.
1069 Presumably HPUX 10, see above, does this.
1071 Hints for porting:
1072 Add your OS to "IFLIST" below.
1073 Get it to compile successfully:
1074 Almost certainly "include"s require attention: see SUNOS5.
1075 In the main code above, arrange for it to be called: see SUNOS5.
1076 Test!
1078 ****************************************************************************/
1080 /* "IFLIST"
1081 * This "if" is a list of ports:
1082 * if defined(OS1) || defined(OS2) || ...
1084 #if defined(SUNOS5)
1086 #if defined(SUNOS5)
1087 #include <sys/fs/vx_solaris.h>
1088 #endif
1089 #include <sys/fs/vx_machdep.h>
1090 #include <sys/fs/vx_layout.h>
1091 #include <sys/fs/vx_quota.h>
1092 #include <sys/fs/vx_aioctl.h>
1093 #include <sys/fs/vx_ioctl.h>
1095 BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
1097 uid_t user_id, euser_id;
1098 int ret;
1099 struct vx_dqblk D;
1100 struct vx_quotctl quotabuf;
1101 struct vx_genioctl genbuf;
1102 pstring qfname;
1103 int file;
1106 * "name" may or may not include a trailing "/quotas".
1107 * Arranging consistency of calling here in "quotas.c" may not be easy and
1108 * it might be easier to examine and adjust it here.
1109 * Fortunately, VxFS seems not to mind at present.
1111 pstrcpy(qfname, name) ;
1112 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1114 euser_id = geteuid();
1115 set_effective_uid(0);
1117 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1118 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1119 set_effective_uid(euser_id);
1120 return(False);
1122 genbuf.ioc_cmd = VX_QUOTACTL;
1123 genbuf.ioc_up = (void *) &quotabuf;
1125 quotabuf.cmd = VX_GETQUOTA;
1126 quotabuf.uid = euser_id;
1127 quotabuf.addr = (caddr_t) &D;
1128 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1129 close(file);
1131 set_effective_uid(euser_id);
1133 if (ret < 0) {
1134 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1135 return(False);
1138 /* If softlimit is zero, set it equal to hardlimit.
1141 if (D.dqb_bsoftlimit==0)
1142 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1144 /* Use softlimit to determine disk space. A user exceeding the quota is told
1145 * that there's no space left. Writes might actually work for a bit if the
1146 * hardlimit is set higher than softlimit. Effectively the disk becomes
1147 * made of rubber latex and begins to expand to accommodate the user :-)
1149 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1150 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1151 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1153 if (D.dqb_bsoftlimit==0)
1154 return(False);
1155 *bsize = DEV_BSIZE;
1156 *dsize = D.dqb_bsoftlimit;
1158 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1159 *dfree = 0;
1160 *dsize = D.dqb_curblocks;
1161 } else
1162 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1164 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1165 path,(double)*bsize,(double)*dfree,(double)*dsize));
1167 return(True);
1170 #endif /* SUNOS5 || ... */
1172 #endif /* VXFS_QUOTA */
1174 #else /* WITH_QUOTAS */
1176 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1178 (*bsize) = 512; /* This value should be ignored */
1180 /* And just to be sure we set some values that hopefully */
1181 /* will be larger that any possible real-world value */
1182 (*dfree) = (SMB_BIG_UINT)-1;
1183 (*dsize) = (SMB_BIG_UINT)-1;
1185 /* As we have select not to use quotas, allways fail */
1186 return False;
1188 #endif /* WITH_QUOTAS */
1190 #else /* HAVE_SYS_QUOTAS */
1191 /* wrapper to the new sys_quota interface
1192 this file should be removed later
1194 BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
1196 int r;
1197 SMB_DISK_QUOTA D;
1198 unid_t id;
1200 id.uid = geteuid();
1202 ZERO_STRUCT(D);
1203 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1205 /* Use softlimit to determine disk space, except when it has been exceeded */
1206 *bsize = D.bsize;
1207 if (r == -1) {
1208 if (errno == EDQUOT) {
1209 *dfree =0;
1210 *dsize =D.curblocks;
1211 return (True);
1212 } else {
1213 goto try_group_quota;
1217 /* Use softlimit to determine disk space, except when it has been exceeded */
1218 if (
1219 (D.softlimit && D.curblocks >= D.softlimit) ||
1220 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1221 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1222 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1224 *dfree = 0;
1225 *dsize = D.curblocks;
1226 } else if (D.softlimit==0 && D.hardlimit==0) {
1227 goto try_group_quota;
1228 } else {
1229 if (D.softlimit == 0)
1230 D.softlimit = D.hardlimit;
1231 *dfree = D.softlimit - D.curblocks;
1232 *dsize = D.softlimit;
1235 return True;
1237 try_group_quota:
1238 id.gid = getegid();
1240 ZERO_STRUCT(D);
1241 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1243 /* Use softlimit to determine disk space, except when it has been exceeded */
1244 *bsize = D.bsize;
1245 if (r == -1) {
1246 if (errno == EDQUOT) {
1247 *dfree =0;
1248 *dsize =D.curblocks;
1249 return (True);
1250 } else {
1251 return False;
1255 /* Use softlimit to determine disk space, except when it has been exceeded */
1256 if (
1257 (D.softlimit && D.curblocks >= D.softlimit) ||
1258 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1259 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1260 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1262 *dfree = 0;
1263 *dsize = D.curblocks;
1264 } else if (D.softlimit==0 && D.hardlimit==0) {
1265 return False;
1266 } else {
1267 if (D.softlimit == 0)
1268 D.softlimit = D.hardlimit;
1269 *dfree = D.softlimit - D.curblocks;
1270 *dsize = D.softlimit;
1273 return (True);
1275 #endif /* HAVE_SYS_QUOTAS */