s3: Remove close_fn from idmap_methods
[Samba.git] / source3 / smbd / quotas.c
blobad3973f754ed45732e64746fcd92ef0c549e54c6
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;
77 * nfs quota support
78 * (essentially taken from FreeBSD / SUNOS5 section)
80 #include <rpc/rpc.h>
81 #include <rpc/types.h>
82 #include <rpcsvc/rquota.h>
83 #ifdef HAVE_RPC_NETTYPE_H
84 #include <rpc/nettype.h>
85 #endif
86 #include <rpc/xdr.h>
88 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
90 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
91 return(0);
92 if (!xdr_int(xdrsp, &args->gqa_uid))
93 return(0);
94 return (1);
97 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
99 int quotastat;
101 if (!xdr_int(xdrsp, &quotastat)) {
102 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
103 return 0;
105 gqr->status = quotastat;
107 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
108 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
109 return 0;
111 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
112 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
113 return 0;
115 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
116 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
117 return 0;
119 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
120 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
121 return 0;
123 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
124 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
125 return 0;
127 return 1;
130 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize,
131 uint64_t *dfree, uint64_t *dsize)
133 uid_t uid = euser_id;
134 LINUX_SMB_DISK_QUOTA D;
135 char *mnttype = nfspath;
136 CLIENT *clnt;
137 struct getquota_rslt gqr;
138 struct getquota_args args;
139 char *cutstr, *pathname, *host, *testpath;
140 int len;
141 static struct timeval timeout = {2,0};
142 enum clnt_stat clnt_stat;
143 bool ret = True;
145 *bsize = *dfree = *dsize = (uint64_t)0;
147 len=strcspn(mnttype, ":");
148 pathname=strstr(mnttype, ":");
149 cutstr = (char *) SMB_MALLOC(len+1);
150 if (!cutstr)
151 return False;
153 memset(cutstr, '\0', len+1);
154 host = strncat(cutstr,mnttype, sizeof(char) * len );
155 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
156 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
157 testpath=strchr_m(mnttype, ':');
158 args.gqa_pathp = testpath+1;
159 args.gqa_uid = uid;
161 DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers "
162 "\"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS,
163 "udp"));
165 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
166 ret = False;
167 goto out;
170 clnt->cl_auth = authunix_create_default();
171 DEBUG(9,("nfs_quotas: auth_success\n"));
173 clnt_stat=clnt_call(clnt,
174 RQUOTAPROC_GETQUOTA,
175 (const xdrproc_t)my_xdr_getquota_args,
176 (caddr_t)&args,
177 (const xdrproc_t)my_xdr_getquota_rslt,
178 (caddr_t)&gqr, timeout);
180 if (clnt_stat != RPC_SUCCESS) {
181 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
182 ret = False;
183 goto out;
187 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
188 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
189 * something sensible.
192 switch (gqr.status) {
193 case 0:
194 DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n",
195 gqr.status));
196 ret = False;
197 goto out;
199 case 1:
200 DEBUG(9,("nfs_quotas: Good quota data\n"));
201 D.softlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
202 D.hardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
203 D.curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
204 break;
206 case 2:
207 case 3:
208 D.softlimit = 1;
209 D.curblocks = 1;
210 DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n",
211 gqr.status));
212 break;
214 default:
215 DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! "
216 "Error \"%i\" \n", gqr.status));
217 break;
220 DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... "
221 "status \"%i\" bsize \"%i\" active? \"%i\" bhard "
222 "\"%i\" bsoft \"%i\" curb \"%i\" \n",
223 gqr.status,
224 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
225 gqr.getquota_rslt_u.gqr_rquota.rq_active,
226 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
227 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
228 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
230 if (D.softlimit == 0)
231 D.softlimit = D.hardlimit;
232 if (D.softlimit == 0)
233 return False;
235 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
236 *dsize = D.softlimit;
238 if (D.curblocks == 1)
239 *bsize = DEV_BSIZE;
241 if (D.curblocks > D.softlimit) {
242 *dfree = 0;
243 *dsize = D.curblocks;
244 } else
245 *dfree = D.softlimit - D.curblocks;
247 out:
249 if (clnt) {
250 if (clnt->cl_auth)
251 auth_destroy(clnt->cl_auth);
252 clnt_destroy(clnt);
255 DEBUG(5, ("nfs_quotas: For path \"%s\" returning "
256 "bsize %.0f, dfree %.0f, dsize %.0f\n",
257 args.gqa_pathp, (double)*bsize, (double)*dfree,
258 (double)*dsize));
260 SAFE_FREE(cutstr);
261 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
262 return ret;
265 /* end of nfs quota section */
267 #ifdef HAVE_LINUX_DQBLK_XFS_H
268 #include <linux/dqblk_xfs.h>
270 /****************************************************************************
271 Abstract out the XFS Quota Manager quota get call.
272 ****************************************************************************/
274 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
276 struct fs_disk_quota D;
277 int ret;
279 ZERO_STRUCT(D);
281 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
283 if (ret)
284 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
286 if (ret)
287 return ret;
289 dp->bsize = (uint64_t)512;
290 dp->softlimit = (uint64_t)D.d_blk_softlimit;
291 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
292 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
293 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
294 dp->curinodes = (uint64_t)D.d_icount;
295 dp->curblocks = (uint64_t)D.d_bcount;
297 return ret;
299 #else
300 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
302 DEBUG(0,("XFS quota support not available\n"));
303 errno = ENOSYS;
304 return -1;
306 #endif
309 /****************************************************************************
310 Abstract out the old and new Linux quota get calls.
311 ****************************************************************************/
313 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
315 struct v1_kern_dqblk D;
316 int ret;
318 ZERO_STRUCT(D);
320 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
322 if (ret && errno != EDQUOT)
323 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
325 if (ret && errno != EDQUOT)
326 return ret;
328 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
329 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
330 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
331 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
332 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
333 dp->curinodes = (uint64_t)D.dqb_curinodes;
334 dp->curblocks = (uint64_t)D.dqb_curblocks;
336 return ret;
339 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
341 struct v2_kern_dqblk D;
342 int ret;
344 ZERO_STRUCT(D);
346 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
348 if (ret && errno != EDQUOT)
349 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
351 if (ret && errno != EDQUOT)
352 return ret;
354 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
355 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
356 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
357 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
358 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
359 dp->curinodes = (uint64_t)D.dqb_curinodes;
360 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
362 return ret;
365 /****************************************************************************
366 Brand-new generic quota interface.
367 ****************************************************************************/
369 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
371 struct if_dqblk D;
372 int ret;
374 ZERO_STRUCT(D);
376 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
378 if (ret && errno != EDQUOT)
379 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
381 if (ret && errno != EDQUOT)
382 return ret;
384 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
385 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
386 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
387 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
388 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
389 dp->curinodes = (uint64_t)D.dqb_curinodes;
390 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
392 return ret;
395 /****************************************************************************
396 Try to get the disk space from disk quotas (LINUX version).
397 ****************************************************************************/
399 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
401 int r;
402 SMB_STRUCT_STAT S;
403 FILE *fp;
404 LINUX_SMB_DISK_QUOTA D;
405 struct mntent *mnt;
406 SMB_DEV_T devno;
407 int found;
408 uid_t euser_id;
409 gid_t egrp_id;
411 ZERO_STRUCT(D);
413 euser_id = geteuid();
414 egrp_id = getegid();
416 /* find the block device file */
418 if (sys_stat(path, &S, false) == -1 )
419 return(False) ;
421 devno = S.st_ex_dev ;
423 if ((fp = setmntent(MOUNTED,"r")) == NULL)
424 return(False) ;
426 found = False ;
428 while ((mnt = getmntent(fp))) {
429 if (sys_stat(mnt->mnt_dir, &S, false) == -1)
430 continue ;
432 if (S.st_ex_dev == devno) {
433 found = True ;
434 break;
438 endmntent(fp) ;
440 if (!found)
441 return(False);
443 become_root();
445 if (strcmp(mnt->mnt_type, "nfs") == 0) {
446 bool retval;
447 retval = nfs_quotas(mnt->mnt_fsname , euser_id, bsize, dfree, dsize);
448 unbecome_root();
449 return retval;
452 if (strcmp(mnt->mnt_type, "xfs")==0) {
453 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
454 } else {
455 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
456 if (r == -1 && errno != EDQUOT) {
457 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
458 if (r == -1 && errno != EDQUOT)
459 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
463 unbecome_root();
465 /* Use softlimit to determine disk space, except when it has been exceeded */
466 *bsize = D.bsize;
467 if (r == -1) {
468 if (errno == EDQUOT) {
469 *dfree =0;
470 *dsize =D.curblocks;
471 return (True);
472 } else {
473 return(False);
477 /* Use softlimit to determine disk space, except when it has been exceeded */
478 if (
479 (D.softlimit && D.curblocks >= D.softlimit) ||
480 (D.hardlimit && D.curblocks >= D.hardlimit) ||
481 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
482 (D.ihardlimit && D.curinodes>=D.ihardlimit)
484 *dfree = 0;
485 *dsize = D.curblocks;
486 } else if (D.softlimit==0 && D.hardlimit==0) {
487 return(False);
488 } else {
489 if (D.softlimit == 0)
490 D.softlimit = D.hardlimit;
491 *dfree = D.softlimit - D.curblocks;
492 *dsize = D.softlimit;
495 return (True);
498 #elif defined(CRAY)
500 #include <sys/quota.h>
501 #include <mntent.h>
503 /****************************************************************************
504 try to get the disk space from disk quotas (CRAY VERSION)
505 ****************************************************************************/
507 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
509 struct mntent *mnt;
510 FILE *fd;
511 SMB_STRUCT_STAT sbuf;
512 SMB_DEV_T devno ;
513 struct q_request request ;
514 struct qf_header header ;
515 int quota_default = 0 ;
516 bool found = false;
518 if (sys_stat(path, &sbuf, false) == -1) {
519 return false;
522 devno = sbuf.st_ex_dev ;
524 if ((fd = setmntent(KMTAB)) == NULL) {
525 return false;
528 while ((mnt = getmntent(fd)) != NULL) {
529 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
530 continue;
532 if (sbuf.st_ex_dev == devno) {
533 found = frue ;
534 break;
538 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
539 endmntent(fd);
540 if (!found) {
541 return false;
544 if (!name) {
545 return false;
548 request.qf_magic = QF_MAGIC ;
549 request.qf_entry.id = geteuid() ;
551 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
552 return false;
555 if (!request.user) {
556 return False;
559 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
560 if (!quota_default) {
561 if (quotactl(name, Q_GETHEADER, &header) == -1) {
562 return false;
563 } else {
564 quota_default = header.user_h.def_fq;
567 *dfree = quota_default;
568 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
569 *dfree = 0;
570 } else {
571 *dfree = request.qf_entry.user_q.f_quota;
574 *dsize = request.qf_entry.user_q.f_use;
576 if (*dfree < *dsize) {
577 *dfree = 0;
578 } else {
579 *dfree -= *dsize;
582 *bsize = 4096 ; /* Cray blocksize */
583 return true;
587 #elif defined(SUNOS5) || defined(SUNOS4)
589 #include <fcntl.h>
590 #include <sys/param.h>
591 #if defined(SUNOS5)
592 #include <sys/fs/ufs_quota.h>
593 #include <sys/mnttab.h>
594 #include <sys/mntent.h>
595 #else /* defined(SUNOS4) */
596 #include <ufs/quota.h>
597 #include <mntent.h>
598 #endif
600 #if defined(SUNOS5)
602 /****************************************************************************
603 Allows querying of remote hosts for quotas on NFS mounted shares.
604 Supports normal NFS and AMD mounts.
605 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
606 ****************************************************************************/
608 #include <rpc/rpc.h>
609 #include <rpc/types.h>
610 #include <rpcsvc/rquota.h>
611 #include <rpc/nettype.h>
612 #include <rpc/xdr.h>
614 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
616 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
617 return(0);
618 if (!xdr_int(xdrsp, &args->gqa_uid))
619 return(0);
620 return (1);
623 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
625 int quotastat;
627 if (!xdr_int(xdrsp, &quotastat)) {
628 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
629 return 0;
631 gqr->status = quotastat;
633 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
634 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
635 return 0;
637 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
638 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
639 return 0;
641 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
642 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
643 return 0;
645 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
646 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
647 return 0;
649 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
650 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
651 return 0;
653 return (1);
656 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
657 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
659 uid_t uid = euser_id;
660 struct dqblk D;
661 char *mnttype = nfspath;
662 CLIENT *clnt;
663 struct getquota_rslt gqr;
664 struct getquota_args args;
665 char *cutstr, *pathname, *host, *testpath;
666 int len;
667 static struct timeval timeout = {2,0};
668 enum clnt_stat clnt_stat;
669 bool ret = True;
671 *bsize = *dfree = *dsize = (uint64_t)0;
673 len=strcspn(mnttype, ":");
674 pathname=strstr(mnttype, ":");
675 cutstr = (char *) SMB_MALLOC(len+1);
676 if (!cutstr)
677 return False;
679 memset(cutstr, '\0', len+1);
680 host = strncat(cutstr,mnttype, sizeof(char) * len );
681 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
682 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
683 testpath=strchr_m(mnttype, ':');
684 args.gqa_pathp = testpath+1;
685 args.gqa_uid = uid;
687 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
689 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
690 ret = False;
691 goto out;
694 clnt->cl_auth = authunix_create_default();
695 DEBUG(9,("nfs_quotas: auth_success\n"));
697 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
699 if (clnt_stat != RPC_SUCCESS) {
700 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
701 ret = False;
702 goto out;
706 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
707 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
708 * something sensible.
711 switch (gqr.status) {
712 case 0:
713 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
714 ret = False;
715 goto out;
717 case 1:
718 DEBUG(9,("nfs_quotas: Good quota data\n"));
719 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
720 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
721 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
722 break;
724 case 2:
725 case 3:
726 D.dqb_bsoftlimit = 1;
727 D.dqb_curblocks = 1;
728 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
729 break;
731 default:
732 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
733 break;
736 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",
737 gqr.status,
738 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
739 gqr.getquota_rslt_u.gqr_rquota.rq_active,
740 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
741 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
742 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
744 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
745 *dsize = D.dqb_bsoftlimit;
747 if (D.dqb_curblocks == 1)
748 *bsize = 512;
750 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
751 *dfree = 0;
752 *dsize = D.dqb_curblocks;
753 } else
754 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
756 out:
758 if (clnt) {
759 if (clnt->cl_auth)
760 auth_destroy(clnt->cl_auth);
761 clnt_destroy(clnt);
764 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
766 SAFE_FREE(cutstr);
767 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
768 return ret;
770 #endif
772 /****************************************************************************
773 try to get the disk space from disk quotas (SunOS & Solaris2 version)
774 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
775 ****************************************************************************/
777 bool disk_quotas(const char *path,
778 uint64_t *bsize,
779 uint64_t *dfree,
780 uint64_t *dsize)
782 uid_t euser_id;
783 int ret;
784 struct dqblk D;
785 #if defined(SUNOS5)
786 struct quotctl command;
787 int file;
788 struct mnttab mnt;
789 #else /* SunOS4 */
790 struct mntent *mnt;
791 #endif
792 char *name = NULL;
793 FILE *fd;
794 SMB_STRUCT_STAT sbuf;
795 SMB_DEV_T devno;
796 bool found = false;
798 euser_id = geteuid();
800 if (sys_stat(path, &sbuf, false) == -1) {
801 return false;
804 devno = sbuf.st_ex_dev ;
805 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
806 path, (unsigned int)devno));
807 #if defined(SUNOS5)
808 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
809 return false;
812 while (getmntent(fd, &mnt) == 0) {
813 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
814 continue;
817 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
818 mnt.mnt_mountp, (unsigned int)devno));
820 /* quotas are only on vxfs, UFS or NFS */
821 if ((sbuf.st_ex_dev == devno) && (
822 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
823 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
824 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
825 found = true;
826 name = talloc_asprintf(talloc_tos(),
827 "%s/quotas",
828 mnt.mnt_mountp);
829 break;
833 fclose(fd);
834 #else /* SunOS4 */
835 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
836 return false;
839 while ((mnt = getmntent(fd)) != NULL) {
840 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
841 continue;
843 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
844 mnt->mnt_dir,
845 (unsigned int)sbuf.st_ex_dev));
846 if (sbuf.st_ex_dev == devno) {
847 found = true;
848 name = talloc_strdup(talloc_tos(),
849 mnt->mnt_fsname);
850 break;
854 endmntent(fd);
855 #endif
856 if (!found) {
857 return false;
860 if (!name) {
861 return false;
863 become_root();
865 #if defined(SUNOS5)
866 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
867 bool retval;
868 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
869 mnt.mnt_special));
870 retval = nfs_quotas(mnt.mnt_special,
871 euser_id, bsize, dfree, dsize);
872 unbecome_root();
873 return retval;
876 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
877 if((file=sys_open(name, O_RDONLY,0))<0) {
878 unbecome_root();
879 return false;
881 command.op = Q_GETQUOTA;
882 command.uid = euser_id;
883 command.addr = (caddr_t) &D;
884 ret = ioctl(file, Q_QUOTACTL, &command);
885 close(file);
886 #else
887 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
888 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
889 #endif
891 unbecome_root();
893 if (ret < 0) {
894 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
895 strerror(errno) ));
897 #if defined(SUNOS5) && defined(VXFS_QUOTA)
898 /* If normal quotactl() fails, try vxfs private calls */
899 set_effective_uid(euser_id);
900 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
901 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
902 bool retval;
903 retval = disk_quotas_vxfs(name, path,
904 bsize, dfree, dsize);
905 return retval;
907 #else
908 return false;
909 #endif
912 /* If softlimit is zero, set it equal to hardlimit.
915 if (D.dqb_bsoftlimit==0) {
916 D.dqb_bsoftlimit = D.dqb_bhardlimit;
919 /* Use softlimit to determine disk space. A user exceeding the quota
920 * is told that there's no space left. Writes might actually work for
921 * a bit if the hardlimit is set higher than softlimit. Effectively
922 * the disk becomes made of rubber latex and begins to expand to
923 * accommodate the user :-)
926 if (D.dqb_bsoftlimit==0)
927 return(False);
928 *bsize = DEV_BSIZE;
929 *dsize = D.dqb_bsoftlimit;
931 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
932 *dfree = 0;
933 *dsize = D.dqb_curblocks;
934 } else {
935 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
938 DEBUG(5,("disk_quotas for path \"%s\" returning "
939 "bsize %.0f, dfree %.0f, dsize %.0f\n",
940 path,(double)*bsize,(double)*dfree,(double)*dsize));
942 return true;
946 #elif defined(OSF1)
947 #include <ufs/quota.h>
949 /****************************************************************************
950 try to get the disk space from disk quotas - OSF1 version
951 ****************************************************************************/
953 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
955 int r, save_errno;
956 struct dqblk D;
957 SMB_STRUCT_STAT S;
958 uid_t euser_id;
961 * This code presumes that OSF1 will only
962 * give out quota info when the real uid
963 * matches the effective uid. JRA.
965 euser_id = geteuid();
966 save_re_uid();
967 if (set_re_uid() != 0) return False;
969 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
970 if (r) {
971 save_errno = errno;
974 restore_re_uid();
976 *bsize = DEV_BSIZE;
978 if (r)
980 if (save_errno == EDQUOT) /* disk quota exceeded */
982 *dfree = 0;
983 *dsize = D.dqb_curblocks;
984 return (True);
986 else
987 return (False);
990 /* If softlimit is zero, set it equal to hardlimit.
993 if (D.dqb_bsoftlimit==0)
994 D.dqb_bsoftlimit = D.dqb_bhardlimit;
996 /* Use softlimit to determine disk space, except when it has been exceeded */
998 if (D.dqb_bsoftlimit==0)
999 return(False);
1001 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
1002 *dfree = 0;
1003 *dsize = D.dqb_curblocks;
1004 } else {
1005 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1006 *dsize = D.dqb_bsoftlimit;
1008 return (True);
1011 #elif defined (IRIX6)
1012 /****************************************************************************
1013 try to get the disk space from disk quotas (IRIX 6.2 version)
1014 ****************************************************************************/
1016 #include <sys/quota.h>
1017 #include <mntent.h>
1019 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1021 uid_t euser_id;
1022 int r;
1023 struct dqblk D;
1024 struct fs_disk_quota F;
1025 SMB_STRUCT_STAT S;
1026 FILE *fp;
1027 struct mntent *mnt;
1028 SMB_DEV_T devno;
1029 int found;
1031 /* find the block device file */
1033 if ( sys_stat(path, &S, false) == -1 ) {
1034 return(False) ;
1037 devno = S.st_ex_dev ;
1039 fp = setmntent(MOUNTED,"r");
1040 found = False ;
1042 while ((mnt = getmntent(fp))) {
1043 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
1044 continue ;
1045 if (S.st_ex_dev == devno) {
1046 found = True ;
1047 break ;
1050 endmntent(fp) ;
1052 if (!found) {
1053 return(False);
1056 euser_id=geteuid();
1057 become_root();
1059 /* Use softlimit to determine disk space, except when it has been exceeded */
1061 *bsize = 512;
1063 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
1065 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
1067 unbecome_root();
1069 if (r==-1)
1070 return(False);
1072 /* Use softlimit to determine disk space, except when it has been exceeded */
1073 if (
1074 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
1075 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
1076 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
1077 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
1080 *dfree = 0;
1081 *dsize = D.dqb_curblocks;
1083 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
1085 return(False);
1087 else
1089 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1090 *dsize = D.dqb_bsoftlimit;
1094 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
1096 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
1098 unbecome_root();
1100 if (r==-1)
1102 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
1103 return(False);
1106 /* No quota for this user. */
1107 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1109 return(False);
1112 /* Use softlimit to determine disk space, except when it has been exceeded */
1113 if (
1114 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1115 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1116 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1117 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1120 *dfree = 0;
1121 *dsize = F.d_bcount;
1123 else
1125 *dfree = (F.d_blk_softlimit - F.d_bcount);
1126 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1130 else
1132 unbecome_root();
1133 return(False);
1136 return (True);
1140 #else
1142 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1143 #include <ufs/ufs/quota.h>
1144 #include <machine/param.h>
1145 #elif AIX
1146 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1147 #include <jfs/quota.h>
1148 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1149 #define dqb_curfiles dqb_curinodes
1150 #define dqb_fhardlimit dqb_ihardlimit
1151 #define dqb_fsoftlimit dqb_isoftlimit
1152 #ifdef _AIXVERSION_530
1153 #include <sys/statfs.h>
1154 #include <sys/vmount.h>
1155 #endif /* AIX 5.3 */
1156 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1157 #include <sys/quota.h>
1158 #include <devnm.h>
1159 #endif
1161 #if defined(__FreeBSD__) || defined(__DragonFly__)
1163 #include <rpc/rpc.h>
1164 #include <rpc/types.h>
1165 #include <rpcsvc/rquota.h>
1166 #ifdef HAVE_RPC_NETTYPE_H
1167 #include <rpc/nettype.h>
1168 #endif
1169 #include <rpc/xdr.h>
1171 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1173 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1174 return(0);
1175 if (!xdr_int(xdrsp, &args->gqa_uid))
1176 return(0);
1177 return (1);
1180 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1182 int quotastat;
1184 if (!xdr_int(xdrsp, &quotastat)) {
1185 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1186 return 0;
1188 gqr->status = quotastat;
1190 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1191 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1192 return 0;
1194 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1195 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1196 return 0;
1198 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1199 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1200 return 0;
1202 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1203 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1204 return 0;
1206 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1207 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1208 return 0;
1210 return (1);
1213 /* Works on FreeBSD, too. :-) */
1214 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1216 uid_t uid = euser_id;
1217 struct dqblk D;
1218 char *mnttype = nfspath;
1219 CLIENT *clnt;
1220 struct getquota_rslt gqr;
1221 struct getquota_args args;
1222 char *cutstr, *pathname, *host, *testpath;
1223 int len;
1224 static struct timeval timeout = {2,0};
1225 enum clnt_stat clnt_stat;
1226 bool ret = True;
1228 *bsize = *dfree = *dsize = (uint64_t)0;
1230 len=strcspn(mnttype, ":");
1231 pathname=strstr(mnttype, ":");
1232 cutstr = (char *) SMB_MALLOC(len+1);
1233 if (!cutstr)
1234 return False;
1236 memset(cutstr, '\0', len+1);
1237 host = strncat(cutstr,mnttype, sizeof(char) * len );
1238 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1239 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1240 testpath=strchr_m(mnttype, ':');
1241 args.gqa_pathp = testpath+1;
1242 args.gqa_uid = uid;
1244 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1246 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1247 ret = False;
1248 goto out;
1251 clnt->cl_auth = authunix_create_default();
1252 DEBUG(9,("nfs_quotas: auth_success\n"));
1254 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);
1256 if (clnt_stat != RPC_SUCCESS) {
1257 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1258 ret = False;
1259 goto out;
1263 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1264 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1265 * something sensible.
1268 switch (gqr.status) {
1269 case 0:
1270 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1271 ret = False;
1272 goto out;
1274 case 1:
1275 DEBUG(9,("nfs_quotas: Good quota data\n"));
1276 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1277 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1278 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1279 break;
1281 case 2:
1282 case 3:
1283 D.dqb_bsoftlimit = 1;
1284 D.dqb_curblocks = 1;
1285 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1286 break;
1288 default:
1289 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1290 break;
1293 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",
1294 gqr.status,
1295 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1296 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1297 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1298 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1299 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1301 if (D.dqb_bsoftlimit == 0)
1302 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1303 if (D.dqb_bsoftlimit == 0)
1304 return False;
1306 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1307 *dsize = D.dqb_bsoftlimit;
1309 if (D.dqb_curblocks == 1)
1310 *bsize = DEV_BSIZE;
1312 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1313 *dfree = 0;
1314 *dsize = D.dqb_curblocks;
1315 } else
1316 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1318 out:
1320 if (clnt) {
1321 if (clnt->cl_auth)
1322 auth_destroy(clnt->cl_auth);
1323 clnt_destroy(clnt);
1326 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1328 SAFE_FREE(cutstr);
1329 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1330 return ret;
1333 #endif
1335 /****************************************************************************
1336 try to get the disk space from disk quotas - default version
1337 ****************************************************************************/
1339 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1341 int r;
1342 struct dqblk D;
1343 uid_t euser_id;
1344 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1345 char dev_disk[256];
1346 SMB_STRUCT_STAT S;
1348 /* find the block device file */
1350 #ifdef HPUX
1351 /* Need to set the cache flag to 1 for HPUX. Seems
1352 * to have a significant performance boost when
1353 * lstat calls on /dev access this function.
1355 if ((sys_stat(path, &S, false)<0)
1356 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1357 #else
1358 if ((sys_stat(path, &S, false)<0)
1359 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1360 return (False);
1361 #endif /* ifdef HPUX */
1363 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1365 euser_id = geteuid();
1367 #ifdef HPUX
1368 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1369 save_re_uid();
1370 if (set_re_uid() != 0) return False;
1372 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1374 restore_re_uid();
1375 #else
1376 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1378 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1379 gid_t egrp_id;
1380 #if defined(__FreeBSD__) || defined(__DragonFly__)
1381 SMB_DEV_T devno;
1382 struct statfs *mnts;
1383 SMB_STRUCT_STAT st;
1384 int mntsize, i;
1386 if (sys_stat(path, &st, false) < 0)
1387 return False;
1388 devno = st.st_ex_dev;
1390 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1391 if (mntsize <= 0)
1392 return False;
1394 for (i = 0; i < mntsize; i++) {
1395 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1396 return False;
1397 if (st.st_ex_dev == devno)
1398 break;
1400 if (i == mntsize)
1401 return False;
1402 #endif
1404 become_root();
1406 #if defined(__FreeBSD__) || defined(__DragonFly__)
1407 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1408 bool retval;
1409 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1410 unbecome_root();
1411 return retval;
1413 #endif
1415 egrp_id = getegid();
1416 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1418 /* As FreeBSD has group quotas, if getting the user
1419 quota fails, try getting the group instead. */
1420 if (r) {
1421 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1424 unbecome_root();
1426 #elif defined(AIX)
1427 /* AIX has both USER and GROUP quotas:
1428 Get the USER quota (ohnielse@fysik.dtu.dk) */
1429 #ifdef _AIXVERSION_530
1431 struct statfs statbuf;
1432 quota64_t user_quota;
1433 if (statfs(path,&statbuf) != 0)
1434 return False;
1435 if(statbuf.f_vfstype == MNT_J2)
1437 /* For some reason we need to be root for jfs2 */
1438 become_root();
1439 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1440 unbecome_root();
1441 /* Copy results to old struct to let the following code work as before */
1442 D.dqb_curblocks = user_quota.bused;
1443 D.dqb_bsoftlimit = user_quota.bsoft;
1444 D.dqb_bhardlimit = user_quota.bhard;
1445 D.dqb_curfiles = user_quota.iused;
1446 D.dqb_fsoftlimit = user_quota.isoft;
1447 D.dqb_fhardlimit = user_quota.ihard;
1449 else if(statbuf.f_vfstype == MNT_JFS)
1451 #endif /* AIX 5.3 */
1452 save_re_uid();
1453 if (set_re_uid() != 0)
1454 return False;
1455 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1456 restore_re_uid();
1457 #ifdef _AIXVERSION_530
1459 else
1460 r = 1; /* Fail for other FS-types */
1462 #endif /* AIX 5.3 */
1463 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1464 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1465 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1466 #endif /* HPUX */
1468 /* Use softlimit to determine disk space, except when it has been exceeded */
1469 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1470 *bsize = DEV_BSIZE;
1471 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1472 *bsize = 1024;
1473 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1475 if (r)
1477 if (errno == EDQUOT)
1479 *dfree =0;
1480 *dsize =D.dqb_curblocks;
1481 return (True);
1483 else return(False);
1486 /* If softlimit is zero, set it equal to hardlimit.
1489 if (D.dqb_bsoftlimit==0)
1490 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1492 if (D.dqb_bsoftlimit==0)
1493 return(False);
1494 /* Use softlimit to determine disk space, except when it has been exceeded */
1495 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1496 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1497 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1498 #endif
1500 *dfree = 0;
1501 *dsize = D.dqb_curblocks;
1503 else {
1504 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1505 *dsize = D.dqb_bsoftlimit;
1507 return (True);
1510 #endif
1512 #if defined(VXFS_QUOTA)
1514 /****************************************************************************
1515 Try to get the disk space from Veritas disk quotas.
1516 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1518 Background assumptions:
1519 Potentially under many Operating Systems. Initially Solaris 2.
1521 My guess is that Veritas is largely, though not entirely,
1522 independent of OS. So I have separated it out.
1524 There may be some details. For example, OS-specific "include" files.
1526 It is understood that HPUX 10 somehow gets Veritas quotas without
1527 any special effort; if so, this routine need not be compiled in.
1528 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1530 Warning:
1531 It is understood that Veritas do not publicly support this ioctl interface.
1532 Rather their preference would be for the user (us) to call the native
1533 OS and then for the OS itself to call through to the VxFS filesystem.
1534 Presumably HPUX 10, see above, does this.
1536 Hints for porting:
1537 Add your OS to "IFLIST" below.
1538 Get it to compile successfully:
1539 Almost certainly "include"s require attention: see SUNOS5.
1540 In the main code above, arrange for it to be called: see SUNOS5.
1541 Test!
1543 ****************************************************************************/
1545 /* "IFLIST"
1546 * This "if" is a list of ports:
1547 * if defined(OS1) || defined(OS2) || ...
1549 #if defined(SUNOS5)
1551 #if defined(SUNOS5)
1552 #include <sys/fs/vx_solaris.h>
1553 #endif
1554 #include <sys/fs/vx_machdep.h>
1555 #include <sys/fs/vx_layout.h>
1556 #include <sys/fs/vx_quota.h>
1557 #include <sys/fs/vx_aioctl.h>
1558 #include <sys/fs/vx_ioctl.h>
1560 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1562 uid_t user_id, euser_id;
1563 int ret;
1564 struct vx_dqblk D;
1565 struct vx_quotctl quotabuf;
1566 struct vx_genioctl genbuf;
1567 char *qfname;
1568 int file;
1571 * "name" may or may not include a trailing "/quotas".
1572 * Arranging consistency of calling here in "quotas.c" may not be easy and
1573 * it might be easier to examine and adjust it here.
1574 * Fortunately, VxFS seems not to mind at present.
1576 qfname = talloc_strdup(talloc_tos(), name);
1577 if (!qfname) {
1578 return false;
1580 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1582 euser_id = geteuid();
1583 set_effective_uid(0);
1585 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1586 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1587 set_effective_uid(euser_id);
1588 return(False);
1590 genbuf.ioc_cmd = VX_QUOTACTL;
1591 genbuf.ioc_up = (void *) &quotabuf;
1593 quotabuf.cmd = VX_GETQUOTA;
1594 quotabuf.uid = euser_id;
1595 quotabuf.addr = (caddr_t) &D;
1596 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1597 close(file);
1599 set_effective_uid(euser_id);
1601 if (ret < 0) {
1602 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1603 return(False);
1606 /* If softlimit is zero, set it equal to hardlimit.
1609 if (D.dqb_bsoftlimit==0)
1610 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1612 /* Use softlimit to determine disk space. A user exceeding the quota is told
1613 * that there's no space left. Writes might actually work for a bit if the
1614 * hardlimit is set higher than softlimit. Effectively the disk becomes
1615 * made of rubber latex and begins to expand to accommodate the user :-)
1617 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1618 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1619 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1621 if (D.dqb_bsoftlimit==0)
1622 return(False);
1623 *bsize = DEV_BSIZE;
1624 *dsize = D.dqb_bsoftlimit;
1626 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1627 *dfree = 0;
1628 *dsize = D.dqb_curblocks;
1629 } else
1630 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1632 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1633 path,(double)*bsize,(double)*dfree,(double)*dsize));
1635 return(True);
1638 #endif /* SUNOS5 || ... */
1640 #endif /* VXFS_QUOTA */
1642 #else /* WITH_QUOTAS */
1644 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1646 (*bsize) = 512; /* This value should be ignored */
1648 /* And just to be sure we set some values that hopefully */
1649 /* will be larger that any possible real-world value */
1650 (*dfree) = (uint64_t)-1;
1651 (*dsize) = (uint64_t)-1;
1653 /* As we have select not to use quotas, allways fail */
1654 return false;
1656 #endif /* WITH_QUOTAS */
1658 #else /* HAVE_SYS_QUOTAS */
1659 /* wrapper to the new sys_quota interface
1660 this file should be removed later
1662 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1664 int r;
1665 SMB_DISK_QUOTA D;
1666 unid_t id;
1668 id.uid = geteuid();
1670 ZERO_STRUCT(D);
1671 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1673 /* Use softlimit to determine disk space, except when it has been exceeded */
1674 *bsize = D.bsize;
1675 if (r == -1) {
1676 if (errno == EDQUOT) {
1677 *dfree =0;
1678 *dsize =D.curblocks;
1679 return (True);
1680 } else {
1681 goto try_group_quota;
1685 /* Use softlimit to determine disk space, except when it has been exceeded */
1686 if (
1687 (D.softlimit && D.curblocks >= D.softlimit) ||
1688 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1689 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1690 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1692 *dfree = 0;
1693 *dsize = D.curblocks;
1694 } else if (D.softlimit==0 && D.hardlimit==0) {
1695 goto try_group_quota;
1696 } else {
1697 if (D.softlimit == 0)
1698 D.softlimit = D.hardlimit;
1699 *dfree = D.softlimit - D.curblocks;
1700 *dsize = D.softlimit;
1703 return True;
1705 try_group_quota:
1706 id.gid = getegid();
1708 ZERO_STRUCT(D);
1709 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1711 /* Use softlimit to determine disk space, except when it has been exceeded */
1712 *bsize = D.bsize;
1713 if (r == -1) {
1714 if (errno == EDQUOT) {
1715 *dfree =0;
1716 *dsize =D.curblocks;
1717 return (True);
1718 } else {
1719 return False;
1723 /* Use softlimit to determine disk space, except when it has been exceeded */
1724 if (
1725 (D.softlimit && D.curblocks >= D.softlimit) ||
1726 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1727 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1728 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1730 *dfree = 0;
1731 *dsize = D.curblocks;
1732 } else if (D.softlimit==0 && D.hardlimit==0) {
1733 return False;
1734 } else {
1735 if (D.softlimit == 0)
1736 D.softlimit = D.hardlimit;
1737 *dfree = D.softlimit - D.curblocks;
1738 *dsize = D.softlimit;
1741 return (True);
1743 #endif /* HAVE_SYS_QUOTAS */