s4-netlogon: implement dcesrv_netr_DsRAddressToSitenamesExW
[Samba/aatanasov.git] / source3 / smbd / quotas.c
blob43b700935e1f86961935914a24218b5810488699
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 3 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, see <http://www.gnu.org/licenses/>.
21 /*
22 * This is one of the most system dependent parts of Samba, and its
23 * done a litle differently. Each system has its own way of doing
24 * things :-(
27 #include "includes.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_QUOTA
32 #ifndef HAVE_SYS_QUOTAS
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
37 #endif
39 #ifdef WITH_QUOTAS
41 #if defined(VXFS_QUOTA)
44 * In addition to their native filesystems, some systems have Veritas VxFS.
45 * Declare here, define at end: reduces likely "include" interaction problems.
46 * David Lee <T.D.Lee@durham.ac.uk>
48 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
50 #endif /* VXFS_QUOTA */
52 #ifdef LINUX
54 #include <sys/types.h>
55 #include <mntent.h>
58 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
59 * So we include all the files has *should* be in the system into a large,
60 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
63 #include "samba_linux_quota.h"
65 typedef struct _LINUX_SMB_DISK_QUOTA {
66 uint64_t bsize;
67 uint64_t hardlimit; /* In bsize units. */
68 uint64_t softlimit; /* In bsize units. */
69 uint64_t curblocks; /* In bsize units. */
70 uint64_t ihardlimit; /* inode hard limit. */
71 uint64_t isoftlimit; /* inode soft limit. */
72 uint64_t curinodes; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA;
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
79 /****************************************************************************
80 Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
85 struct fs_disk_quota D;
86 int ret;
88 ZERO_STRUCT(D);
90 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
92 if (ret)
93 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
95 if (ret)
96 return ret;
98 dp->bsize = (uint64_t)512;
99 dp->softlimit = (uint64_t)D.d_blk_softlimit;
100 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
101 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
102 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
103 dp->curinodes = (uint64_t)D.d_icount;
104 dp->curblocks = (uint64_t)D.d_bcount;
106 return ret;
108 #else
109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
111 DEBUG(0,("XFS quota support not available\n"));
112 errno = ENOSYS;
113 return -1;
115 #endif
118 /****************************************************************************
119 Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
124 struct v1_kern_dqblk D;
125 int ret;
127 ZERO_STRUCT(D);
129 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
131 if (ret && errno != EDQUOT)
132 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
134 if (ret && errno != EDQUOT)
135 return ret;
137 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
138 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
139 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
140 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
141 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
142 dp->curinodes = (uint64_t)D.dqb_curinodes;
143 dp->curblocks = (uint64_t)D.dqb_curblocks;
145 return ret;
148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
150 struct v2_kern_dqblk D;
151 int ret;
153 ZERO_STRUCT(D);
155 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
157 if (ret && errno != EDQUOT)
158 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
160 if (ret && errno != EDQUOT)
161 return ret;
163 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
164 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
165 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
166 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
167 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
168 dp->curinodes = (uint64_t)D.dqb_curinodes;
169 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
171 return ret;
174 /****************************************************************************
175 Brand-new generic quota interface.
176 ****************************************************************************/
178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
180 struct if_dqblk D;
181 int ret;
183 ZERO_STRUCT(D);
185 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
187 if (ret && errno != EDQUOT)
188 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
190 if (ret && errno != EDQUOT)
191 return ret;
193 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
194 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
195 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
196 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
197 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
198 dp->curinodes = (uint64_t)D.dqb_curinodes;
199 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
201 return ret;
204 /****************************************************************************
205 Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
208 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
210 int r;
211 SMB_STRUCT_STAT S;
212 FILE *fp;
213 LINUX_SMB_DISK_QUOTA D;
214 struct mntent *mnt;
215 SMB_DEV_T devno;
216 int found;
217 uid_t euser_id;
218 gid_t egrp_id;
220 ZERO_STRUCT(D);
222 euser_id = geteuid();
223 egrp_id = getegid();
225 /* find the block device file */
227 if ( sys_stat(path, &S) == -1 )
228 return(False) ;
230 devno = S.st_ex_dev ;
232 if ((fp = setmntent(MOUNTED,"r")) == NULL)
233 return(False) ;
235 found = False ;
237 while ((mnt = getmntent(fp))) {
238 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
239 continue ;
241 if (S.st_ex_dev == devno) {
242 found = True ;
243 break;
247 endmntent(fp) ;
249 if (!found)
250 return(False);
252 become_root();
254 if (strcmp(mnt->mnt_type, "xfs")==0) {
255 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
256 } else {
257 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
258 if (r == -1 && errno != EDQUOT) {
259 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
260 if (r == -1 && errno != EDQUOT)
261 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
265 unbecome_root();
267 /* Use softlimit to determine disk space, except when it has been exceeded */
268 *bsize = D.bsize;
269 if (r == -1) {
270 if (errno == EDQUOT) {
271 *dfree =0;
272 *dsize =D.curblocks;
273 return (True);
274 } else {
275 return(False);
279 /* Use softlimit to determine disk space, except when it has been exceeded */
280 if (
281 (D.softlimit && D.curblocks >= D.softlimit) ||
282 (D.hardlimit && D.curblocks >= D.hardlimit) ||
283 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
284 (D.ihardlimit && D.curinodes>=D.ihardlimit)
286 *dfree = 0;
287 *dsize = D.curblocks;
288 } else if (D.softlimit==0 && D.hardlimit==0) {
289 return(False);
290 } else {
291 if (D.softlimit == 0)
292 D.softlimit = D.hardlimit;
293 *dfree = D.softlimit - D.curblocks;
294 *dsize = D.softlimit;
297 return (True);
300 #elif defined(CRAY)
302 #include <sys/quota.h>
303 #include <mntent.h>
305 /****************************************************************************
306 try to get the disk space from disk quotas (CRAY VERSION)
307 ****************************************************************************/
309 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
311 struct mntent *mnt;
312 FILE *fd;
313 SMB_STRUCT_STAT sbuf;
314 SMB_DEV_T devno ;
315 struct q_request request ;
316 struct qf_header header ;
317 int quota_default = 0 ;
318 bool found = false;
320 if (sys_stat(path,&sbuf) == -1) {
321 return false;
324 devno = sbuf.st_ex_dev ;
326 if ((fd = setmntent(KMTAB)) == NULL) {
327 return false;
330 while ((mnt = getmntent(fd)) != NULL) {
331 if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
332 continue;
334 if (sbuf.st_ex_dev == devno) {
335 found = frue ;
336 break;
340 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
341 endmntent(fd);
342 if (!found) {
343 return false;
346 if (!name) {
347 return false;
350 request.qf_magic = QF_MAGIC ;
351 request.qf_entry.id = geteuid() ;
353 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
354 return false;
357 if (!request.user) {
358 return False;
361 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
362 if (!quota_default) {
363 if (quotactl(name, Q_GETHEADER, &header) == -1) {
364 return false;
365 } else {
366 quota_default = header.user_h.def_fq;
369 *dfree = quota_default;
370 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
371 *dfree = 0;
372 } else {
373 *dfree = request.qf_entry.user_q.f_quota;
376 *dsize = request.qf_entry.user_q.f_use;
378 if (*dfree < *dsize) {
379 *dfree = 0;
380 } else {
381 *dfree -= *dsize;
384 *bsize = 4096 ; /* Cray blocksize */
385 return true;
389 #elif defined(SUNOS5) || defined(SUNOS4)
391 #include <fcntl.h>
392 #include <sys/param.h>
393 #if defined(SUNOS5)
394 #include <sys/fs/ufs_quota.h>
395 #include <sys/mnttab.h>
396 #include <sys/mntent.h>
397 #else /* defined(SUNOS4) */
398 #include <ufs/quota.h>
399 #include <mntent.h>
400 #endif
402 #if defined(SUNOS5)
404 /****************************************************************************
405 Allows querying of remote hosts for quotas on NFS mounted shares.
406 Supports normal NFS and AMD mounts.
407 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
408 ****************************************************************************/
410 #include <rpc/rpc.h>
411 #include <rpc/types.h>
412 #include <rpcsvc/rquota.h>
413 #include <rpc/nettype.h>
414 #include <rpc/xdr.h>
416 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
418 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
419 return(0);
420 if (!xdr_int(xdrsp, &args->gqa_uid))
421 return(0);
422 return (1);
425 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
427 int quotastat;
429 if (!xdr_int(xdrsp, &quotastat)) {
430 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
431 return 0;
433 gqr->status = quotastat;
435 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
436 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
437 return 0;
439 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
440 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
441 return 0;
443 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
444 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
445 return 0;
447 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
448 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
449 return 0;
451 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
452 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
453 return 0;
455 return (1);
458 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
459 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
461 uid_t uid = euser_id;
462 struct dqblk D;
463 char *mnttype = nfspath;
464 CLIENT *clnt;
465 struct getquota_rslt gqr;
466 struct getquota_args args;
467 char *cutstr, *pathname, *host, *testpath;
468 int len;
469 static struct timeval timeout = {2,0};
470 enum clnt_stat clnt_stat;
471 bool ret = True;
473 *bsize = *dfree = *dsize = (uint64_t)0;
475 len=strcspn(mnttype, ":");
476 pathname=strstr(mnttype, ":");
477 cutstr = (char *) SMB_MALLOC(len+1);
478 if (!cutstr)
479 return False;
481 memset(cutstr, '\0', len+1);
482 host = strncat(cutstr,mnttype, sizeof(char) * len );
483 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
484 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
485 testpath=strchr_m(mnttype, ':');
486 args.gqa_pathp = testpath+1;
487 args.gqa_uid = uid;
489 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
491 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
492 ret = False;
493 goto out;
496 clnt->cl_auth = authunix_create_default();
497 DEBUG(9,("nfs_quotas: auth_success\n"));
499 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
501 if (clnt_stat != RPC_SUCCESS) {
502 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
503 ret = False;
504 goto out;
508 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
509 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
510 * something sensible.
513 switch (gqr.status) {
514 case 0:
515 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
516 ret = False;
517 goto out;
519 case 1:
520 DEBUG(9,("nfs_quotas: Good quota data\n"));
521 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
522 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
523 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
524 break;
526 case 2:
527 case 3:
528 D.dqb_bsoftlimit = 1;
529 D.dqb_curblocks = 1;
530 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
531 break;
533 default:
534 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
535 break;
538 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",
539 gqr.status,
540 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
541 gqr.getquota_rslt_u.gqr_rquota.rq_active,
542 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
543 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
544 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
546 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
547 *dsize = D.dqb_bsoftlimit;
549 if (D.dqb_curblocks == 1)
550 *bsize = 512;
552 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
553 *dfree = 0;
554 *dsize = D.dqb_curblocks;
555 } else
556 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
558 out:
560 if (clnt) {
561 if (clnt->cl_auth)
562 auth_destroy(clnt->cl_auth);
563 clnt_destroy(clnt);
566 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
568 SAFE_FREE(cutstr);
569 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
570 return ret;
572 #endif
574 /****************************************************************************
575 try to get the disk space from disk quotas (SunOS & Solaris2 version)
576 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
577 ****************************************************************************/
579 bool disk_quotas(const char *path,
580 uint64_t *bsize,
581 uint64_t *dfree,
582 uint64_t *dsize)
584 uid_t euser_id;
585 int ret;
586 struct dqblk D;
587 #if defined(SUNOS5)
588 struct quotctl command;
589 int file;
590 struct mnttab mnt;
591 #else /* SunOS4 */
592 struct mntent *mnt;
593 #endif
594 char *name = NULL;
595 FILE *fd;
596 SMB_STRUCT_STAT sbuf;
597 SMB_DEV_T devno;
598 bool found = false;
600 euser_id = geteuid();
602 if (sys_stat(path,&sbuf) == -1) {
603 return false;
606 devno = sbuf.st_ex_dev ;
607 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
608 path, (unsigned int)devno));
609 #if defined(SUNOS5)
610 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
611 return false;
614 while (getmntent(fd, &mnt) == 0) {
615 if (sys_stat(mnt.mnt_mountp, &sbuf) == -1) {
616 continue;
619 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
620 mnt.mnt_mountp, (unsigned int)devno));
622 /* quotas are only on vxfs, UFS or NFS */
623 if ((sbuf.st_ex_dev == devno) && (
624 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
625 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
626 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
627 found = true;
628 name = talloc_asprintf(talloc_tos(),
629 "%s/quotas",
630 mnt.mnt_mountp);
631 break;
635 fclose(fd);
636 #else /* SunOS4 */
637 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
638 return false;
641 while ((mnt = getmntent(fd)) != NULL) {
642 if (sys_stat(mnt->mnt_dir,&sbuf) == -1) {
643 continue;
645 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
646 mnt->mnt_dir,
647 (unsigned int)sbuf.st_ex_dev));
648 if (sbuf.st_ex_dev == devno) {
649 found = true;
650 name = talloc_strdup(talloc_tos(),
651 mnt->mnt_fsname);
652 break;
656 endmntent(fd);
657 #endif
658 if (!found) {
659 return false;
662 if (!name) {
663 return false;
665 become_root();
667 #if defined(SUNOS5)
668 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
669 bool retval;
670 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
671 mnt.mnt_special));
672 retval = nfs_quotas(mnt.mnt_special,
673 euser_id, bsize, dfree, dsize);
674 unbecome_root();
675 return retval;
678 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
679 if((file=sys_open(name, O_RDONLY,0))<0) {
680 unbecome_root();
681 return false;
683 command.op = Q_GETQUOTA;
684 command.uid = euser_id;
685 command.addr = (caddr_t) &D;
686 ret = ioctl(file, Q_QUOTACTL, &command);
687 close(file);
688 #else
689 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
690 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
691 #endif
693 unbecome_root();
695 if (ret < 0) {
696 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
697 strerror(errno) ));
699 #if defined(SUNOS5) && defined(VXFS_QUOTA)
700 /* If normal quotactl() fails, try vxfs private calls */
701 set_effective_uid(euser_id);
702 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
703 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
704 bool retval;
705 retval = disk_quotas_vxfs(name, path,
706 bsize, dfree, dsize);
707 return retval;
709 #else
710 return false;
711 #endif
714 /* If softlimit is zero, set it equal to hardlimit.
717 if (D.dqb_bsoftlimit==0) {
718 D.dqb_bsoftlimit = D.dqb_bhardlimit;
721 /* Use softlimit to determine disk space. A user exceeding the quota
722 * is told that there's no space left. Writes might actually work for
723 * a bit if the hardlimit is set higher than softlimit. Effectively
724 * the disk becomes made of rubber latex and begins to expand to
725 * accommodate the user :-)
728 if (D.dqb_bsoftlimit==0)
729 return(False);
730 *bsize = DEV_BSIZE;
731 *dsize = D.dqb_bsoftlimit;
733 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
734 *dfree = 0;
735 *dsize = D.dqb_curblocks;
736 } else {
737 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
740 DEBUG(5,("disk_quotas for path \"%s\" returning "
741 "bsize %.0f, dfree %.0f, dsize %.0f\n",
742 path,(double)*bsize,(double)*dfree,(double)*dsize));
744 return true;
748 #elif defined(OSF1)
749 #include <ufs/quota.h>
751 /****************************************************************************
752 try to get the disk space from disk quotas - OSF1 version
753 ****************************************************************************/
755 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
757 int r, save_errno;
758 struct dqblk D;
759 SMB_STRUCT_STAT S;
760 uid_t euser_id;
763 * This code presumes that OSF1 will only
764 * give out quota info when the real uid
765 * matches the effective uid. JRA.
767 euser_id = geteuid();
768 save_re_uid();
769 if (set_re_uid() != 0) return False;
771 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
772 if (r) {
773 save_errno = errno;
776 restore_re_uid();
778 *bsize = DEV_BSIZE;
780 if (r)
782 if (save_errno == EDQUOT) /* disk quota exceeded */
784 *dfree = 0;
785 *dsize = D.dqb_curblocks;
786 return (True);
788 else
789 return (False);
792 /* If softlimit is zero, set it equal to hardlimit.
795 if (D.dqb_bsoftlimit==0)
796 D.dqb_bsoftlimit = D.dqb_bhardlimit;
798 /* Use softlimit to determine disk space, except when it has been exceeded */
800 if (D.dqb_bsoftlimit==0)
801 return(False);
803 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
804 *dfree = 0;
805 *dsize = D.dqb_curblocks;
806 } else {
807 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
808 *dsize = D.dqb_bsoftlimit;
810 return (True);
813 #elif defined (IRIX6)
814 /****************************************************************************
815 try to get the disk space from disk quotas (IRIX 6.2 version)
816 ****************************************************************************/
818 #include <sys/quota.h>
819 #include <mntent.h>
821 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
823 uid_t euser_id;
824 int r;
825 struct dqblk D;
826 struct fs_disk_quota F;
827 SMB_STRUCT_STAT S;
828 FILE *fp;
829 struct mntent *mnt;
830 SMB_DEV_T devno;
831 int found;
833 /* find the block device file */
835 if ( sys_stat(path, &S) == -1 ) {
836 return(False) ;
839 devno = S.st_ex_dev ;
841 fp = setmntent(MOUNTED,"r");
842 found = False ;
844 while ((mnt = getmntent(fp))) {
845 if ( sys_stat(mnt->mnt_dir,&S) == -1 )
846 continue ;
847 if (S.st_ex_dev == devno) {
848 found = True ;
849 break ;
852 endmntent(fp) ;
854 if (!found) {
855 return(False);
858 euser_id=geteuid();
859 become_root();
861 /* Use softlimit to determine disk space, except when it has been exceeded */
863 *bsize = 512;
865 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
867 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
869 unbecome_root();
871 if (r==-1)
872 return(False);
874 /* Use softlimit to determine disk space, except when it has been exceeded */
875 if (
876 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
877 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
878 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
879 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
882 *dfree = 0;
883 *dsize = D.dqb_curblocks;
885 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
887 return(False);
889 else
891 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
892 *dsize = D.dqb_bsoftlimit;
896 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
898 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
900 unbecome_root();
902 if (r==-1)
904 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
905 return(False);
908 /* No quota for this user. */
909 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
911 return(False);
914 /* Use softlimit to determine disk space, except when it has been exceeded */
915 if (
916 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
917 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
918 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
919 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
922 *dfree = 0;
923 *dsize = F.d_bcount;
925 else
927 *dfree = (F.d_blk_softlimit - F.d_bcount);
928 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
932 else
934 unbecome_root();
935 return(False);
938 return (True);
942 #else
944 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
945 #include <ufs/ufs/quota.h>
946 #include <machine/param.h>
947 #elif AIX
948 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
949 #include <jfs/quota.h>
950 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
951 #define dqb_curfiles dqb_curinodes
952 #define dqb_fhardlimit dqb_ihardlimit
953 #define dqb_fsoftlimit dqb_isoftlimit
954 #ifdef _AIXVERSION_530
955 #include <sys/statfs.h>
956 #include <sys/vmount.h>
957 #endif /* AIX 5.3 */
958 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
959 #include <sys/quota.h>
960 #include <devnm.h>
961 #endif
963 #if defined(__FreeBSD__) || defined(__DragonFly__)
965 #include <rpc/rpc.h>
966 #include <rpc/types.h>
967 #include <rpcsvc/rquota.h>
968 #ifdef HAVE_RPC_NETTYPE_H
969 #include <rpc/nettype.h>
970 #endif
971 #include <rpc/xdr.h>
973 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
975 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
976 return(0);
977 if (!xdr_int(xdrsp, &args->gqa_uid))
978 return(0);
979 return (1);
982 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
984 int quotastat;
986 if (!xdr_int(xdrsp, &quotastat)) {
987 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
988 return 0;
990 gqr->status = quotastat;
992 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
993 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
994 return 0;
996 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
997 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
998 return 0;
1000 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1001 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1002 return 0;
1004 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1005 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1006 return 0;
1008 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1009 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1010 return 0;
1012 return (1);
1015 /* Works on FreeBSD, too. :-) */
1016 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1018 uid_t uid = euser_id;
1019 struct dqblk D;
1020 char *mnttype = nfspath;
1021 CLIENT *clnt;
1022 struct getquota_rslt gqr;
1023 struct getquota_args args;
1024 char *cutstr, *pathname, *host, *testpath;
1025 int len;
1026 static struct timeval timeout = {2,0};
1027 enum clnt_stat clnt_stat;
1028 bool ret = True;
1030 *bsize = *dfree = *dsize = (uint64_t)0;
1032 len=strcspn(mnttype, ":");
1033 pathname=strstr(mnttype, ":");
1034 cutstr = (char *) SMB_MALLOC(len+1);
1035 if (!cutstr)
1036 return False;
1038 memset(cutstr, '\0', len+1);
1039 host = strncat(cutstr,mnttype, sizeof(char) * len );
1040 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1041 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1042 testpath=strchr_m(mnttype, ':');
1043 args.gqa_pathp = testpath+1;
1044 args.gqa_uid = uid;
1046 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1048 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1049 ret = False;
1050 goto out;
1053 clnt->cl_auth = authunix_create_default();
1054 DEBUG(9,("nfs_quotas: auth_success\n"));
1056 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, (const xdrproc_t) my_xdr_getquota_args, (caddr_t)&args, (const xdrproc_t) my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
1058 if (clnt_stat != RPC_SUCCESS) {
1059 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1060 ret = False;
1061 goto out;
1065 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1066 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1067 * something sensible.
1070 switch (gqr.status) {
1071 case 0:
1072 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1073 ret = False;
1074 goto out;
1076 case 1:
1077 DEBUG(9,("nfs_quotas: Good quota data\n"));
1078 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1079 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1080 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1081 break;
1083 case 2:
1084 case 3:
1085 D.dqb_bsoftlimit = 1;
1086 D.dqb_curblocks = 1;
1087 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1088 break;
1090 default:
1091 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1092 break;
1095 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",
1096 gqr.status,
1097 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1098 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1099 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1100 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1101 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1103 if (D.dqb_bsoftlimit == 0)
1104 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1105 if (D.dqb_bsoftlimit == 0)
1106 return False;
1108 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1109 *dsize = D.dqb_bsoftlimit;
1111 if (D.dqb_curblocks == 1)
1112 *bsize = DEV_BSIZE;
1114 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1115 *dfree = 0;
1116 *dsize = D.dqb_curblocks;
1117 } else
1118 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1120 out:
1122 if (clnt) {
1123 if (clnt->cl_auth)
1124 auth_destroy(clnt->cl_auth);
1125 clnt_destroy(clnt);
1128 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1130 SAFE_FREE(cutstr);
1131 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1132 return ret;
1135 #endif
1137 /****************************************************************************
1138 try to get the disk space from disk quotas - default version
1139 ****************************************************************************/
1141 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1143 int r;
1144 struct dqblk D;
1145 uid_t euser_id;
1146 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1147 char dev_disk[256];
1148 SMB_STRUCT_STAT S;
1150 /* find the block device file */
1152 #ifdef HPUX
1153 /* Need to set the cache flag to 1 for HPUX. Seems
1154 * to have a significant performance boost when
1155 * lstat calls on /dev access this function.
1157 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1158 #else
1159 if ((sys_stat(path, &S)<0) || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1160 return (False);
1161 #endif /* ifdef HPUX */
1163 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1165 euser_id = geteuid();
1167 #ifdef HPUX
1168 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1169 save_re_uid();
1170 if (set_re_uid() != 0) return False;
1172 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1174 restore_re_uid();
1175 #else
1176 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1178 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1179 gid_t egrp_id;
1180 #if defined(__FreeBSD__) || defined(__DragonFly__)
1181 SMB_DEV_T devno;
1182 struct statfs *mnts;
1183 SMB_STRUCT_STAT st;
1184 int mntsize, i;
1186 if (sys_stat(path,&st) < 0)
1187 return False;
1188 devno = st.st_ex_dev;
1190 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1191 if (mntsize <= 0)
1192 return False;
1194 for (i = 0; i < mntsize; i++) {
1195 if (sys_stat(mnts[i].f_mntonname,&st) < 0)
1196 return False;
1197 if (st.st_ex_dev == devno)
1198 break;
1200 if (i == mntsize)
1201 return False;
1202 #endif
1204 become_root();
1206 #if defined(__FreeBSD__) || defined(__DragonFly__)
1207 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1208 bool retval;
1209 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1210 unbecome_root();
1211 return retval;
1213 #endif
1215 egrp_id = getegid();
1216 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1218 /* As FreeBSD has group quotas, if getting the user
1219 quota fails, try getting the group instead. */
1220 if (r) {
1221 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1224 unbecome_root();
1226 #elif defined(AIX)
1227 /* AIX has both USER and GROUP quotas:
1228 Get the USER quota (ohnielse@fysik.dtu.dk) */
1229 #ifdef _AIXVERSION_530
1231 struct statfs statbuf;
1232 quota64_t user_quota;
1233 if (statfs(path,&statbuf) != 0)
1234 return False;
1235 if(statbuf.f_vfstype == MNT_J2)
1237 /* For some reason we need to be root for jfs2 */
1238 become_root();
1239 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1240 unbecome_root();
1241 /* Copy results to old struct to let the following code work as before */
1242 D.dqb_curblocks = user_quota.bused;
1243 D.dqb_bsoftlimit = user_quota.bsoft;
1244 D.dqb_bhardlimit = user_quota.bhard;
1245 D.dqb_curfiles = user_quota.iused;
1246 D.dqb_fsoftlimit = user_quota.isoft;
1247 D.dqb_fhardlimit = user_quota.ihard;
1249 else if(statbuf.f_vfstype == MNT_JFS)
1251 #endif /* AIX 5.3 */
1252 save_re_uid();
1253 if (set_re_uid() != 0)
1254 return False;
1255 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1256 restore_re_uid();
1257 #ifdef _AIXVERSION_530
1259 else
1260 r = 1; /* Fail for other FS-types */
1262 #endif /* AIX 5.3 */
1263 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1264 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1265 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1266 #endif /* HPUX */
1268 /* Use softlimit to determine disk space, except when it has been exceeded */
1269 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1270 *bsize = DEV_BSIZE;
1271 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1272 *bsize = 1024;
1273 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1275 if (r)
1277 if (errno == EDQUOT)
1279 *dfree =0;
1280 *dsize =D.dqb_curblocks;
1281 return (True);
1283 else return(False);
1286 /* If softlimit is zero, set it equal to hardlimit.
1289 if (D.dqb_bsoftlimit==0)
1290 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1292 if (D.dqb_bsoftlimit==0)
1293 return(False);
1294 /* Use softlimit to determine disk space, except when it has been exceeded */
1295 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1296 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1297 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1298 #endif
1300 *dfree = 0;
1301 *dsize = D.dqb_curblocks;
1303 else {
1304 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1305 *dsize = D.dqb_bsoftlimit;
1307 return (True);
1310 #endif
1312 #if defined(VXFS_QUOTA)
1314 /****************************************************************************
1315 Try to get the disk space from Veritas disk quotas.
1316 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1318 Background assumptions:
1319 Potentially under many Operating Systems. Initially Solaris 2.
1321 My guess is that Veritas is largely, though not entirely,
1322 independent of OS. So I have separated it out.
1324 There may be some details. For example, OS-specific "include" files.
1326 It is understood that HPUX 10 somehow gets Veritas quotas without
1327 any special effort; if so, this routine need not be compiled in.
1328 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1330 Warning:
1331 It is understood that Veritas do not publicly support this ioctl interface.
1332 Rather their preference would be for the user (us) to call the native
1333 OS and then for the OS itself to call through to the VxFS filesystem.
1334 Presumably HPUX 10, see above, does this.
1336 Hints for porting:
1337 Add your OS to "IFLIST" below.
1338 Get it to compile successfully:
1339 Almost certainly "include"s require attention: see SUNOS5.
1340 In the main code above, arrange for it to be called: see SUNOS5.
1341 Test!
1343 ****************************************************************************/
1345 /* "IFLIST"
1346 * This "if" is a list of ports:
1347 * if defined(OS1) || defined(OS2) || ...
1349 #if defined(SUNOS5)
1351 #if defined(SUNOS5)
1352 #include <sys/fs/vx_solaris.h>
1353 #endif
1354 #include <sys/fs/vx_machdep.h>
1355 #include <sys/fs/vx_layout.h>
1356 #include <sys/fs/vx_quota.h>
1357 #include <sys/fs/vx_aioctl.h>
1358 #include <sys/fs/vx_ioctl.h>
1360 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1362 uid_t user_id, euser_id;
1363 int ret;
1364 struct vx_dqblk D;
1365 struct vx_quotctl quotabuf;
1366 struct vx_genioctl genbuf;
1367 char *qfname;
1368 int file;
1371 * "name" may or may not include a trailing "/quotas".
1372 * Arranging consistency of calling here in "quotas.c" may not be easy and
1373 * it might be easier to examine and adjust it here.
1374 * Fortunately, VxFS seems not to mind at present.
1376 qfname = talloc_strdup(talloc_tos(), name);
1377 if (!qfname) {
1378 return false;
1380 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1382 euser_id = geteuid();
1383 set_effective_uid(0);
1385 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1386 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1387 set_effective_uid(euser_id);
1388 return(False);
1390 genbuf.ioc_cmd = VX_QUOTACTL;
1391 genbuf.ioc_up = (void *) &quotabuf;
1393 quotabuf.cmd = VX_GETQUOTA;
1394 quotabuf.uid = euser_id;
1395 quotabuf.addr = (caddr_t) &D;
1396 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1397 close(file);
1399 set_effective_uid(euser_id);
1401 if (ret < 0) {
1402 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1403 return(False);
1406 /* If softlimit is zero, set it equal to hardlimit.
1409 if (D.dqb_bsoftlimit==0)
1410 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1412 /* Use softlimit to determine disk space. A user exceeding the quota is told
1413 * that there's no space left. Writes might actually work for a bit if the
1414 * hardlimit is set higher than softlimit. Effectively the disk becomes
1415 * made of rubber latex and begins to expand to accommodate the user :-)
1417 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1418 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1419 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1421 if (D.dqb_bsoftlimit==0)
1422 return(False);
1423 *bsize = DEV_BSIZE;
1424 *dsize = D.dqb_bsoftlimit;
1426 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1427 *dfree = 0;
1428 *dsize = D.dqb_curblocks;
1429 } else
1430 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1432 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1433 path,(double)*bsize,(double)*dfree,(double)*dsize));
1435 return(True);
1438 #endif /* SUNOS5 || ... */
1440 #endif /* VXFS_QUOTA */
1442 #else /* WITH_QUOTAS */
1444 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1446 (*bsize) = 512; /* This value should be ignored */
1448 /* And just to be sure we set some values that hopefully */
1449 /* will be larger that any possible real-world value */
1450 (*dfree) = (uint64_t)-1;
1451 (*dsize) = (uint64_t)-1;
1453 /* As we have select not to use quotas, allways fail */
1454 return false;
1456 #endif /* WITH_QUOTAS */
1458 #else /* HAVE_SYS_QUOTAS */
1459 /* wrapper to the new sys_quota interface
1460 this file should be removed later
1462 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1464 int r;
1465 SMB_DISK_QUOTA D;
1466 unid_t id;
1468 id.uid = geteuid();
1470 ZERO_STRUCT(D);
1471 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1473 /* Use softlimit to determine disk space, except when it has been exceeded */
1474 *bsize = D.bsize;
1475 if (r == -1) {
1476 if (errno == EDQUOT) {
1477 *dfree =0;
1478 *dsize =D.curblocks;
1479 return (True);
1480 } else {
1481 goto try_group_quota;
1485 /* Use softlimit to determine disk space, except when it has been exceeded */
1486 if (
1487 (D.softlimit && D.curblocks >= D.softlimit) ||
1488 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1489 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1490 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1492 *dfree = 0;
1493 *dsize = D.curblocks;
1494 } else if (D.softlimit==0 && D.hardlimit==0) {
1495 goto try_group_quota;
1496 } else {
1497 if (D.softlimit == 0)
1498 D.softlimit = D.hardlimit;
1499 *dfree = D.softlimit - D.curblocks;
1500 *dsize = D.softlimit;
1503 return True;
1505 try_group_quota:
1506 id.gid = getegid();
1508 ZERO_STRUCT(D);
1509 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1511 /* Use softlimit to determine disk space, except when it has been exceeded */
1512 *bsize = D.bsize;
1513 if (r == -1) {
1514 if (errno == EDQUOT) {
1515 *dfree =0;
1516 *dsize =D.curblocks;
1517 return (True);
1518 } else {
1519 return False;
1523 /* Use softlimit to determine disk space, except when it has been exceeded */
1524 if (
1525 (D.softlimit && D.curblocks >= D.softlimit) ||
1526 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1527 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1528 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1530 *dfree = 0;
1531 *dsize = D.curblocks;
1532 } else if (D.softlimit==0 && D.hardlimit==0) {
1533 return False;
1534 } else {
1535 if (D.softlimit == 0)
1536 D.softlimit = D.hardlimit;
1537 *dfree = D.softlimit - D.curblocks;
1538 *dsize = D.softlimit;
1541 return (True);
1543 #endif /* HAVE_SYS_QUOTAS */