talloc: setup the new 'tc' before TC_UNDEFINE_GROW_CHUNK() _talloc_realloc()
[Samba.git] / source3 / smbd / quotas.c
blobc9f85b6ad099aa7e9c5d2b7da634136f5c36f09b
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"
28 #include "smbd/smbd.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 char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *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"
66 typedef struct _LINUX_SMB_DISK_QUOTA {
67 uint64_t bsize;
68 uint64_t hardlimit; /* In bsize units. */
69 uint64_t softlimit; /* In bsize units. */
70 uint64_t curblocks; /* In bsize units. */
71 uint64_t ihardlimit; /* inode hard limit. */
72 uint64_t isoftlimit; /* inode soft limit. */
73 uint64_t curinodes; /* Current used inodes. */
74 } LINUX_SMB_DISK_QUOTA;
78 * nfs quota support
79 * (essentially taken from FreeBSD / SUNOS5 section)
81 #include <rpc/rpc.h>
82 #include <rpc/types.h>
83 #include <rpcsvc/rquota.h>
84 #ifdef HAVE_RPC_NETTYPE_H
85 #include <rpc/nettype.h>
86 #endif
87 #include <rpc/xdr.h>
89 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
91 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
92 return(0);
93 if (!xdr_int(xdrsp, &args->gqa_uid))
94 return(0);
95 return (1);
98 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
100 int quotastat;
102 if (!xdr_int(xdrsp, &quotastat)) {
103 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
104 return 0;
106 gqr->status = quotastat;
108 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
109 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
110 return 0;
112 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
113 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
114 return 0;
116 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
117 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
118 return 0;
120 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
121 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
122 return 0;
124 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
125 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
126 return 0;
128 return 1;
131 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize,
132 uint64_t *dfree, uint64_t *dsize)
134 uid_t uid = euser_id;
135 LINUX_SMB_DISK_QUOTA D;
136 char *mnttype = nfspath;
137 CLIENT *clnt;
138 struct getquota_rslt gqr;
139 struct getquota_args args;
140 char *cutstr, *pathname, *host, *testpath;
141 int len;
142 static struct timeval timeout = {2,0};
143 enum clnt_stat clnt_stat;
144 bool ret = True;
146 *bsize = *dfree = *dsize = (uint64_t)0;
148 len=strcspn(mnttype, ":");
149 pathname=strstr(mnttype, ":");
150 cutstr = (char *) SMB_MALLOC(len+1);
151 if (!cutstr)
152 return False;
154 memset(cutstr, '\0', len+1);
155 host = strncat(cutstr,mnttype, sizeof(char) * len );
156 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
157 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
158 testpath=strchr_m(mnttype, ':');
159 args.gqa_pathp = testpath+1;
160 args.gqa_uid = uid;
162 DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers "
163 "\"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS,
164 "udp"));
166 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
167 ret = False;
168 goto out;
171 clnt->cl_auth = authunix_create_default();
172 DEBUG(9,("nfs_quotas: auth_success\n"));
174 clnt_stat=clnt_call(clnt,
175 RQUOTAPROC_GETQUOTA,
176 (const xdrproc_t)my_xdr_getquota_args,
177 (caddr_t)&args,
178 (const xdrproc_t)my_xdr_getquota_rslt,
179 (caddr_t)&gqr, timeout);
181 if (clnt_stat != RPC_SUCCESS) {
182 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
183 ret = False;
184 goto out;
188 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
189 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
190 * something sensible.
193 switch (gqr.status) {
194 case 0:
195 DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n",
196 gqr.status));
197 ret = False;
198 goto out;
200 case 1:
201 DEBUG(9,("nfs_quotas: Good quota data\n"));
202 D.softlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
203 D.hardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
204 D.curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
205 break;
207 case 2:
208 case 3:
209 D.softlimit = 1;
210 D.curblocks = 1;
211 DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n",
212 gqr.status));
213 break;
215 default:
216 DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! "
217 "Error \"%i\" \n", gqr.status));
218 break;
221 DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... "
222 "status \"%i\" bsize \"%i\" active? \"%i\" bhard "
223 "\"%i\" bsoft \"%i\" curb \"%i\" \n",
224 gqr.status,
225 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
226 gqr.getquota_rslt_u.gqr_rquota.rq_active,
227 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
228 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
229 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
231 if (D.softlimit == 0)
232 D.softlimit = D.hardlimit;
233 if (D.softlimit == 0)
234 return False;
236 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
237 *dsize = D.softlimit;
239 if (D.curblocks == 1)
240 *bsize = DEV_BSIZE;
242 if (D.curblocks > D.softlimit) {
243 *dfree = 0;
244 *dsize = D.curblocks;
245 } else
246 *dfree = D.softlimit - D.curblocks;
248 out:
250 if (clnt) {
251 if (clnt->cl_auth)
252 auth_destroy(clnt->cl_auth);
253 clnt_destroy(clnt);
256 DEBUG(5, ("nfs_quotas: For path \"%s\" returning "
257 "bsize %.0f, dfree %.0f, dsize %.0f\n",
258 args.gqa_pathp, (double)*bsize, (double)*dfree,
259 (double)*dsize));
261 SAFE_FREE(cutstr);
262 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
263 return ret;
266 /* end of nfs quota section */
268 #ifdef HAVE_LINUX_DQBLK_XFS_H
269 #include <linux/dqblk_xfs.h>
271 /****************************************************************************
272 Abstract out the XFS Quota Manager quota get call.
273 ****************************************************************************/
275 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
277 struct fs_disk_quota D;
278 int ret;
280 ZERO_STRUCT(D);
282 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
284 if (ret)
285 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
287 if (ret)
288 return ret;
290 dp->bsize = (uint64_t)512;
291 dp->softlimit = (uint64_t)D.d_blk_softlimit;
292 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
293 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
294 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
295 dp->curinodes = (uint64_t)D.d_icount;
296 dp->curblocks = (uint64_t)D.d_bcount;
298 return ret;
300 #else
301 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
303 DEBUG(0,("XFS quota support not available\n"));
304 errno = ENOSYS;
305 return -1;
307 #endif
310 /****************************************************************************
311 Abstract out the old and new Linux quota get calls.
312 ****************************************************************************/
314 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
316 struct v1_kern_dqblk D;
317 int ret;
319 ZERO_STRUCT(D);
321 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
323 if (ret && errno != EDQUOT)
324 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
326 if (ret && errno != EDQUOT)
327 return ret;
329 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
330 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
331 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
332 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
333 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
334 dp->curinodes = (uint64_t)D.dqb_curinodes;
335 dp->curblocks = (uint64_t)D.dqb_curblocks;
337 return ret;
340 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
342 struct v2_kern_dqblk D;
343 int ret;
345 ZERO_STRUCT(D);
347 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
349 if (ret && errno != EDQUOT)
350 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
352 if (ret && errno != EDQUOT)
353 return ret;
355 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
356 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
357 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
358 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
359 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
360 dp->curinodes = (uint64_t)D.dqb_curinodes;
361 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
363 return ret;
366 /****************************************************************************
367 Brand-new generic quota interface.
368 ****************************************************************************/
370 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
372 struct if_dqblk D;
373 int ret;
375 ZERO_STRUCT(D);
377 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
379 if (ret && errno != EDQUOT)
380 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
382 if (ret && errno != EDQUOT)
383 return ret;
385 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
386 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
387 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
388 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
389 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
390 dp->curinodes = (uint64_t)D.dqb_curinodes;
391 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
393 return ret;
396 /****************************************************************************
397 Try to get the disk space from disk quotas (LINUX version).
398 ****************************************************************************/
400 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
402 int r;
403 SMB_STRUCT_STAT S;
404 FILE *fp;
405 LINUX_SMB_DISK_QUOTA D;
406 struct mntent *mnt;
407 SMB_DEV_T devno;
408 int found;
409 uid_t euser_id;
410 gid_t egrp_id;
412 ZERO_STRUCT(D);
414 euser_id = geteuid();
415 egrp_id = getegid();
417 /* find the block device file */
419 if (sys_stat(path, &S, false) == -1 )
420 return(False) ;
422 devno = S.st_ex_dev ;
424 if ((fp = setmntent(MOUNTED,"r")) == NULL)
425 return(False) ;
427 found = False ;
429 while ((mnt = getmntent(fp))) {
430 if (sys_stat(mnt->mnt_dir, &S, false) == -1)
431 continue ;
433 if (S.st_ex_dev == devno) {
434 found = True ;
435 break;
439 endmntent(fp) ;
441 if (!found)
442 return(False);
444 become_root();
446 if (strcmp(mnt->mnt_type, "nfs") == 0) {
447 bool retval;
448 retval = nfs_quotas(mnt->mnt_fsname , euser_id, bsize, dfree, dsize);
449 unbecome_root();
450 return retval;
453 if (strcmp(mnt->mnt_type, "xfs")==0) {
454 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
455 } else {
456 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
457 if (r == -1 && errno != EDQUOT) {
458 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
459 if (r == -1 && errno != EDQUOT)
460 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
464 unbecome_root();
466 /* Use softlimit to determine disk space, except when it has been exceeded */
467 *bsize = D.bsize;
468 if (r == -1) {
469 if (errno == EDQUOT) {
470 *dfree =0;
471 *dsize =D.curblocks;
472 return (True);
473 } else {
474 return(False);
478 /* Use softlimit to determine disk space, except when it has been exceeded */
479 if (
480 (D.softlimit && D.curblocks >= D.softlimit) ||
481 (D.hardlimit && D.curblocks >= D.hardlimit) ||
482 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
483 (D.ihardlimit && D.curinodes>=D.ihardlimit)
485 *dfree = 0;
486 *dsize = D.curblocks;
487 } else if (D.softlimit==0 && D.hardlimit==0) {
488 return(False);
489 } else {
490 if (D.softlimit == 0)
491 D.softlimit = D.hardlimit;
492 *dfree = D.softlimit - D.curblocks;
493 *dsize = D.softlimit;
496 return (True);
499 #elif defined(CRAY)
501 #include <sys/quota.h>
502 #include <mntent.h>
504 /****************************************************************************
505 try to get the disk space from disk quotas (CRAY VERSION)
506 ****************************************************************************/
508 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
510 struct mntent *mnt;
511 FILE *fd;
512 SMB_STRUCT_STAT sbuf;
513 SMB_DEV_T devno ;
514 struct q_request request ;
515 struct qf_header header ;
516 int quota_default = 0 ;
517 bool found = false;
519 if (sys_stat(path, &sbuf, false) == -1) {
520 return false;
523 devno = sbuf.st_ex_dev ;
525 if ((fd = setmntent(KMTAB)) == NULL) {
526 return false;
529 while ((mnt = getmntent(fd)) != NULL) {
530 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
531 continue;
533 if (sbuf.st_ex_dev == devno) {
534 found = frue ;
535 break;
539 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
540 endmntent(fd);
541 if (!found) {
542 return false;
545 if (!name) {
546 return false;
549 request.qf_magic = QF_MAGIC ;
550 request.qf_entry.id = geteuid() ;
552 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
553 return false;
556 if (!request.user) {
557 return False;
560 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
561 if (!quota_default) {
562 if (quotactl(name, Q_GETHEADER, &header) == -1) {
563 return false;
564 } else {
565 quota_default = header.user_h.def_fq;
568 *dfree = quota_default;
569 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
570 *dfree = 0;
571 } else {
572 *dfree = request.qf_entry.user_q.f_quota;
575 *dsize = request.qf_entry.user_q.f_use;
577 if (*dfree < *dsize) {
578 *dfree = 0;
579 } else {
580 *dfree -= *dsize;
583 *bsize = 4096 ; /* Cray blocksize */
584 return true;
588 #elif defined(SUNOS5) || defined(SUNOS4)
590 #include <fcntl.h>
591 #include <sys/param.h>
592 #if defined(SUNOS5)
593 #include <sys/fs/ufs_quota.h>
594 #include <sys/mnttab.h>
595 #include <sys/mntent.h>
596 #else /* defined(SUNOS4) */
597 #include <ufs/quota.h>
598 #include <mntent.h>
599 #endif
601 #if defined(SUNOS5)
603 /****************************************************************************
604 Allows querying of remote hosts for quotas on NFS mounted shares.
605 Supports normal NFS and AMD mounts.
606 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
607 ****************************************************************************/
609 #include <rpc/rpc.h>
610 #include <rpc/types.h>
611 #include <rpcsvc/rquota.h>
612 #include <rpc/nettype.h>
613 #include <rpc/xdr.h>
615 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
617 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
618 return(0);
619 if (!xdr_int(xdrsp, &args->gqa_uid))
620 return(0);
621 return (1);
624 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
626 int quotastat;
628 if (!xdr_int(xdrsp, &quotastat)) {
629 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
630 return 0;
632 gqr->status = quotastat;
634 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
635 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
636 return 0;
638 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
639 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
640 return 0;
642 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
643 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
644 return 0;
646 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
647 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
648 return 0;
650 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
651 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
652 return 0;
654 return (1);
657 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
658 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
660 uid_t uid = euser_id;
661 struct dqblk D;
662 char *mnttype = nfspath;
663 CLIENT *clnt;
664 struct getquota_rslt gqr;
665 struct getquota_args args;
666 char *cutstr, *pathname, *host, *testpath;
667 int len;
668 static struct timeval timeout = {2,0};
669 enum clnt_stat clnt_stat;
670 bool ret = True;
672 *bsize = *dfree = *dsize = (uint64_t)0;
674 len=strcspn(mnttype, ":");
675 pathname=strstr(mnttype, ":");
676 cutstr = (char *) SMB_MALLOC(len+1);
677 if (!cutstr)
678 return False;
680 memset(cutstr, '\0', len+1);
681 host = strncat(cutstr,mnttype, sizeof(char) * len );
682 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
683 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
684 testpath=strchr_m(mnttype, ':');
685 args.gqa_pathp = testpath+1;
686 args.gqa_uid = uid;
688 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
690 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
691 ret = False;
692 goto out;
695 clnt->cl_auth = authunix_create_default();
696 DEBUG(9,("nfs_quotas: auth_success\n"));
698 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
700 if (clnt_stat != RPC_SUCCESS) {
701 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
702 ret = False;
703 goto out;
707 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
708 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
709 * something sensible.
712 switch (gqr.status) {
713 case 0:
714 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
715 ret = False;
716 goto out;
718 case 1:
719 DEBUG(9,("nfs_quotas: Good quota data\n"));
720 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
721 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
722 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
723 break;
725 case 2:
726 case 3:
727 D.dqb_bsoftlimit = 1;
728 D.dqb_curblocks = 1;
729 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
730 break;
732 default:
733 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
734 break;
737 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",
738 gqr.status,
739 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
740 gqr.getquota_rslt_u.gqr_rquota.rq_active,
741 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
742 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
743 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
745 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
746 *dsize = D.dqb_bsoftlimit;
748 if (D.dqb_curblocks == 1)
749 *bsize = 512;
751 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
752 *dfree = 0;
753 *dsize = D.dqb_curblocks;
754 } else
755 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
757 out:
759 if (clnt) {
760 if (clnt->cl_auth)
761 auth_destroy(clnt->cl_auth);
762 clnt_destroy(clnt);
765 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
767 SAFE_FREE(cutstr);
768 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
769 return ret;
771 #endif
773 /****************************************************************************
774 try to get the disk space from disk quotas (SunOS & Solaris2 version)
775 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
776 ****************************************************************************/
778 bool disk_quotas(const char *path,
779 uint64_t *bsize,
780 uint64_t *dfree,
781 uint64_t *dsize)
783 uid_t euser_id;
784 int ret;
785 struct dqblk D;
786 #if defined(SUNOS5)
787 struct quotctl command;
788 int file;
789 struct mnttab mnt;
790 #else /* SunOS4 */
791 struct mntent *mnt;
792 #endif
793 char *name = NULL;
794 FILE *fd;
795 SMB_STRUCT_STAT sbuf;
796 SMB_DEV_T devno;
797 bool found = false;
799 euser_id = geteuid();
801 if (sys_stat(path, &sbuf, false) == -1) {
802 return false;
805 devno = sbuf.st_ex_dev ;
806 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
807 path, (unsigned int)devno));
808 #if defined(SUNOS5)
809 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
810 return false;
813 while (getmntent(fd, &mnt) == 0) {
814 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
815 continue;
818 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
819 mnt.mnt_mountp, (unsigned int)devno));
821 /* quotas are only on vxfs, UFS or NFS */
822 if ((sbuf.st_ex_dev == devno) && (
823 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
824 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
825 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
826 found = true;
827 name = talloc_asprintf(talloc_tos(),
828 "%s/quotas",
829 mnt.mnt_mountp);
830 break;
834 fclose(fd);
835 #else /* SunOS4 */
836 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
837 return false;
840 while ((mnt = getmntent(fd)) != NULL) {
841 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
842 continue;
844 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
845 mnt->mnt_dir,
846 (unsigned int)sbuf.st_ex_dev));
847 if (sbuf.st_ex_dev == devno) {
848 found = true;
849 name = talloc_strdup(talloc_tos(),
850 mnt->mnt_fsname);
851 break;
855 endmntent(fd);
856 #endif
857 if (!found) {
858 return false;
861 if (!name) {
862 return false;
864 become_root();
866 #if defined(SUNOS5)
867 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
868 bool retval;
869 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
870 mnt.mnt_special));
871 retval = nfs_quotas(mnt.mnt_special,
872 euser_id, bsize, dfree, dsize);
873 unbecome_root();
874 return retval;
877 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
878 if((file=sys_open(name, O_RDONLY,0))<0) {
879 unbecome_root();
880 return false;
882 command.op = Q_GETQUOTA;
883 command.uid = euser_id;
884 command.addr = (caddr_t) &D;
885 ret = ioctl(file, Q_QUOTACTL, &command);
886 close(file);
887 #else
888 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
889 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
890 #endif
892 unbecome_root();
894 if (ret < 0) {
895 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
896 strerror(errno) ));
898 #if defined(SUNOS5) && defined(VXFS_QUOTA)
899 /* If normal quotactl() fails, try vxfs private calls */
900 set_effective_uid(euser_id);
901 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
902 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
903 bool retval;
904 retval = disk_quotas_vxfs(name, path,
905 bsize, dfree, dsize);
906 return retval;
908 #else
909 return false;
910 #endif
913 /* If softlimit is zero, set it equal to hardlimit.
916 if (D.dqb_bsoftlimit==0) {
917 D.dqb_bsoftlimit = D.dqb_bhardlimit;
920 /* Use softlimit to determine disk space. A user exceeding the quota
921 * is told that there's no space left. Writes might actually work for
922 * a bit if the hardlimit is set higher than softlimit. Effectively
923 * the disk becomes made of rubber latex and begins to expand to
924 * accommodate the user :-)
927 if (D.dqb_bsoftlimit==0)
928 return(False);
929 *bsize = DEV_BSIZE;
930 *dsize = D.dqb_bsoftlimit;
932 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
933 *dfree = 0;
934 *dsize = D.dqb_curblocks;
935 } else {
936 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
939 DEBUG(5,("disk_quotas for path \"%s\" returning "
940 "bsize %.0f, dfree %.0f, dsize %.0f\n",
941 path,(double)*bsize,(double)*dfree,(double)*dsize));
943 return true;
947 #elif defined(OSF1)
948 #include <ufs/quota.h>
950 /****************************************************************************
951 try to get the disk space from disk quotas - OSF1 version
952 ****************************************************************************/
954 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
956 int r, save_errno;
957 struct dqblk D;
958 SMB_STRUCT_STAT S;
959 uid_t euser_id;
962 * This code presumes that OSF1 will only
963 * give out quota info when the real uid
964 * matches the effective uid. JRA.
966 euser_id = geteuid();
967 save_re_uid();
968 if (set_re_uid() != 0) return False;
970 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
971 if (r) {
972 save_errno = errno;
975 restore_re_uid();
977 *bsize = DEV_BSIZE;
979 if (r)
981 if (save_errno == EDQUOT) /* disk quota exceeded */
983 *dfree = 0;
984 *dsize = D.dqb_curblocks;
985 return (True);
987 else
988 return (False);
991 /* If softlimit is zero, set it equal to hardlimit.
994 if (D.dqb_bsoftlimit==0)
995 D.dqb_bsoftlimit = D.dqb_bhardlimit;
997 /* Use softlimit to determine disk space, except when it has been exceeded */
999 if (D.dqb_bsoftlimit==0)
1000 return(False);
1002 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
1003 *dfree = 0;
1004 *dsize = D.dqb_curblocks;
1005 } else {
1006 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1007 *dsize = D.dqb_bsoftlimit;
1009 return (True);
1012 #elif defined (IRIX6)
1013 /****************************************************************************
1014 try to get the disk space from disk quotas (IRIX 6.2 version)
1015 ****************************************************************************/
1017 #include <sys/quota.h>
1018 #include <mntent.h>
1020 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1022 uid_t euser_id;
1023 int r;
1024 struct dqblk D;
1025 struct fs_disk_quota F;
1026 SMB_STRUCT_STAT S;
1027 FILE *fp;
1028 struct mntent *mnt;
1029 SMB_DEV_T devno;
1030 int found;
1032 /* find the block device file */
1034 if ( sys_stat(path, &S, false) == -1 ) {
1035 return(False) ;
1038 devno = S.st_ex_dev ;
1040 fp = setmntent(MOUNTED,"r");
1041 found = False ;
1043 while ((mnt = getmntent(fp))) {
1044 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
1045 continue ;
1046 if (S.st_ex_dev == devno) {
1047 found = True ;
1048 break ;
1051 endmntent(fp) ;
1053 if (!found) {
1054 return(False);
1057 euser_id=geteuid();
1058 become_root();
1060 /* Use softlimit to determine disk space, except when it has been exceeded */
1062 *bsize = 512;
1064 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
1066 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
1068 unbecome_root();
1070 if (r==-1)
1071 return(False);
1073 /* Use softlimit to determine disk space, except when it has been exceeded */
1074 if (
1075 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
1076 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
1077 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
1078 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
1081 *dfree = 0;
1082 *dsize = D.dqb_curblocks;
1084 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
1086 return(False);
1088 else
1090 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1091 *dsize = D.dqb_bsoftlimit;
1095 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
1097 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
1099 unbecome_root();
1101 if (r==-1)
1103 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
1104 return(False);
1107 /* No quota for this user. */
1108 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1110 return(False);
1113 /* Use softlimit to determine disk space, except when it has been exceeded */
1114 if (
1115 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1116 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1117 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1118 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1121 *dfree = 0;
1122 *dsize = F.d_bcount;
1124 else
1126 *dfree = (F.d_blk_softlimit - F.d_bcount);
1127 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1131 else
1133 unbecome_root();
1134 return(False);
1137 return (True);
1141 #else
1143 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1144 #include <ufs/ufs/quota.h>
1145 #include <machine/param.h>
1146 #elif AIX
1147 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1148 #include <jfs/quota.h>
1149 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1150 #define dqb_curfiles dqb_curinodes
1151 #define dqb_fhardlimit dqb_ihardlimit
1152 #define dqb_fsoftlimit dqb_isoftlimit
1153 #ifdef _AIXVERSION_530
1154 #include <sys/statfs.h>
1155 #include <sys/vmount.h>
1156 #endif /* AIX 5.3 */
1157 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1158 #include <sys/quota.h>
1159 #include <devnm.h>
1160 #endif
1162 #if defined(__FreeBSD__) || defined(__DragonFly__)
1164 #include <rpc/rpc.h>
1165 #include <rpc/types.h>
1166 #include <rpcsvc/rquota.h>
1167 #ifdef HAVE_RPC_NETTYPE_H
1168 #include <rpc/nettype.h>
1169 #endif
1170 #include <rpc/xdr.h>
1172 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1174 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1175 return(0);
1176 if (!xdr_int(xdrsp, &args->gqa_uid))
1177 return(0);
1178 return (1);
1181 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1183 int quotastat;
1185 if (!xdr_int(xdrsp, &quotastat)) {
1186 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1187 return 0;
1189 gqr->status = quotastat;
1191 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1192 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1193 return 0;
1195 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1196 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1197 return 0;
1199 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1200 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1201 return 0;
1203 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1204 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1205 return 0;
1207 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1208 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1209 return 0;
1211 return (1);
1214 /* Works on FreeBSD, too. :-) */
1215 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1217 uid_t uid = euser_id;
1218 struct dqblk D;
1219 char *mnttype = nfspath;
1220 CLIENT *clnt;
1221 struct getquota_rslt gqr;
1222 struct getquota_args args;
1223 char *cutstr, *pathname, *host, *testpath;
1224 int len;
1225 static struct timeval timeout = {2,0};
1226 enum clnt_stat clnt_stat;
1227 bool ret = True;
1229 *bsize = *dfree = *dsize = (uint64_t)0;
1231 len=strcspn(mnttype, ":");
1232 pathname=strstr(mnttype, ":");
1233 cutstr = (char *) SMB_MALLOC(len+1);
1234 if (!cutstr)
1235 return False;
1237 memset(cutstr, '\0', len+1);
1238 host = strncat(cutstr,mnttype, sizeof(char) * len );
1239 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1240 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1241 testpath=strchr_m(mnttype, ':');
1242 args.gqa_pathp = testpath+1;
1243 args.gqa_uid = uid;
1245 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1247 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1248 ret = False;
1249 goto out;
1252 clnt->cl_auth = authunix_create_default();
1253 DEBUG(9,("nfs_quotas: auth_success\n"));
1255 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);
1257 if (clnt_stat != RPC_SUCCESS) {
1258 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1259 ret = False;
1260 goto out;
1264 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1265 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1266 * something sensible.
1269 switch (gqr.status) {
1270 case 0:
1271 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1272 ret = False;
1273 goto out;
1275 case 1:
1276 DEBUG(9,("nfs_quotas: Good quota data\n"));
1277 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1278 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1279 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1280 break;
1282 case 2:
1283 case 3:
1284 D.dqb_bsoftlimit = 1;
1285 D.dqb_curblocks = 1;
1286 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1287 break;
1289 default:
1290 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1291 break;
1294 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",
1295 gqr.status,
1296 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1297 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1298 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1299 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1300 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1302 if (D.dqb_bsoftlimit == 0)
1303 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1304 if (D.dqb_bsoftlimit == 0)
1305 return False;
1307 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1308 *dsize = D.dqb_bsoftlimit;
1310 if (D.dqb_curblocks == 1)
1311 *bsize = DEV_BSIZE;
1313 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1314 *dfree = 0;
1315 *dsize = D.dqb_curblocks;
1316 } else
1317 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1319 out:
1321 if (clnt) {
1322 if (clnt->cl_auth)
1323 auth_destroy(clnt->cl_auth);
1324 clnt_destroy(clnt);
1327 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1329 SAFE_FREE(cutstr);
1330 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1331 return ret;
1334 #endif
1336 /****************************************************************************
1337 try to get the disk space from disk quotas - default version
1338 ****************************************************************************/
1340 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1342 int r;
1343 struct dqblk D;
1344 uid_t euser_id;
1345 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1346 char dev_disk[256];
1347 SMB_STRUCT_STAT S;
1349 /* find the block device file */
1351 #ifdef HPUX
1352 /* Need to set the cache flag to 1 for HPUX. Seems
1353 * to have a significant performance boost when
1354 * lstat calls on /dev access this function.
1356 if ((sys_stat(path, &S, false)<0)
1357 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1358 #else
1359 if ((sys_stat(path, &S, false)<0)
1360 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1361 return (False);
1362 #endif /* ifdef HPUX */
1364 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1366 euser_id = geteuid();
1368 #ifdef HPUX
1369 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1370 save_re_uid();
1371 if (set_re_uid() != 0) return False;
1373 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1375 restore_re_uid();
1376 #else
1377 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1379 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1380 gid_t egrp_id;
1381 #if defined(__FreeBSD__) || defined(__DragonFly__)
1382 SMB_DEV_T devno;
1383 struct statfs *mnts;
1384 SMB_STRUCT_STAT st;
1385 int mntsize, i;
1387 if (sys_stat(path, &st, false) < 0)
1388 return False;
1389 devno = st.st_ex_dev;
1391 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1392 if (mntsize <= 0)
1393 return False;
1395 for (i = 0; i < mntsize; i++) {
1396 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1397 return False;
1398 if (st.st_ex_dev == devno)
1399 break;
1401 if (i == mntsize)
1402 return False;
1403 #endif
1405 become_root();
1407 #if defined(__FreeBSD__) || defined(__DragonFly__)
1408 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1409 bool retval;
1410 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1411 unbecome_root();
1412 return retval;
1414 #endif
1416 egrp_id = getegid();
1417 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1419 /* As FreeBSD has group quotas, if getting the user
1420 quota fails, try getting the group instead. */
1421 if (r) {
1422 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1425 unbecome_root();
1427 #elif defined(AIX)
1428 /* AIX has both USER and GROUP quotas:
1429 Get the USER quota (ohnielse@fysik.dtu.dk) */
1430 #ifdef _AIXVERSION_530
1432 struct statfs statbuf;
1433 quota64_t user_quota;
1434 if (statfs(path,&statbuf) != 0)
1435 return False;
1436 if(statbuf.f_vfstype == MNT_J2)
1438 /* For some reason we need to be root for jfs2 */
1439 become_root();
1440 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1441 unbecome_root();
1442 /* Copy results to old struct to let the following code work as before */
1443 D.dqb_curblocks = user_quota.bused;
1444 D.dqb_bsoftlimit = user_quota.bsoft;
1445 D.dqb_bhardlimit = user_quota.bhard;
1446 D.dqb_curfiles = user_quota.iused;
1447 D.dqb_fsoftlimit = user_quota.isoft;
1448 D.dqb_fhardlimit = user_quota.ihard;
1450 else if(statbuf.f_vfstype == MNT_JFS)
1452 #endif /* AIX 5.3 */
1453 save_re_uid();
1454 if (set_re_uid() != 0)
1455 return False;
1456 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1457 restore_re_uid();
1458 #ifdef _AIXVERSION_530
1460 else
1461 r = 1; /* Fail for other FS-types */
1463 #endif /* AIX 5.3 */
1464 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1465 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1466 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1467 #endif /* HPUX */
1469 /* Use softlimit to determine disk space, except when it has been exceeded */
1470 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1471 *bsize = DEV_BSIZE;
1472 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1473 *bsize = 1024;
1474 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1476 if (r)
1478 if (errno == EDQUOT)
1480 *dfree =0;
1481 *dsize =D.dqb_curblocks;
1482 return (True);
1484 else return(False);
1487 /* If softlimit is zero, set it equal to hardlimit.
1490 if (D.dqb_bsoftlimit==0)
1491 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1493 if (D.dqb_bsoftlimit==0)
1494 return(False);
1495 /* Use softlimit to determine disk space, except when it has been exceeded */
1496 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1497 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1498 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1499 #endif
1501 *dfree = 0;
1502 *dsize = D.dqb_curblocks;
1504 else {
1505 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1506 *dsize = D.dqb_bsoftlimit;
1508 return (True);
1511 #endif
1513 #if defined(VXFS_QUOTA)
1515 /****************************************************************************
1516 Try to get the disk space from Veritas disk quotas.
1517 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1519 Background assumptions:
1520 Potentially under many Operating Systems. Initially Solaris 2.
1522 My guess is that Veritas is largely, though not entirely,
1523 independent of OS. So I have separated it out.
1525 There may be some details. For example, OS-specific "include" files.
1527 It is understood that HPUX 10 somehow gets Veritas quotas without
1528 any special effort; if so, this routine need not be compiled in.
1529 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1531 Warning:
1532 It is understood that Veritas do not publicly support this ioctl interface.
1533 Rather their preference would be for the user (us) to call the native
1534 OS and then for the OS itself to call through to the VxFS filesystem.
1535 Presumably HPUX 10, see above, does this.
1537 Hints for porting:
1538 Add your OS to "IFLIST" below.
1539 Get it to compile successfully:
1540 Almost certainly "include"s require attention: see SUNOS5.
1541 In the main code above, arrange for it to be called: see SUNOS5.
1542 Test!
1544 ****************************************************************************/
1546 /* "IFLIST"
1547 * This "if" is a list of ports:
1548 * if defined(OS1) || defined(OS2) || ...
1550 #if defined(SUNOS5)
1552 #if defined(SUNOS5)
1553 #include <sys/fs/vx_solaris.h>
1554 #endif
1555 #include <sys/fs/vx_machdep.h>
1556 #include <sys/fs/vx_layout.h>
1557 #include <sys/fs/vx_quota.h>
1558 #include <sys/fs/vx_aioctl.h>
1559 #include <sys/fs/vx_ioctl.h>
1561 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1563 uid_t user_id, euser_id;
1564 int ret;
1565 struct vx_dqblk D;
1566 struct vx_quotctl quotabuf;
1567 struct vx_genioctl genbuf;
1568 char *qfname;
1569 int file;
1572 * "name" may or may not include a trailing "/quotas".
1573 * Arranging consistency of calling here in "quotas.c" may not be easy and
1574 * it might be easier to examine and adjust it here.
1575 * Fortunately, VxFS seems not to mind at present.
1577 qfname = talloc_strdup(talloc_tos(), name);
1578 if (!qfname) {
1579 return false;
1581 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1583 euser_id = geteuid();
1584 set_effective_uid(0);
1586 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1587 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1588 set_effective_uid(euser_id);
1589 return(False);
1591 genbuf.ioc_cmd = VX_QUOTACTL;
1592 genbuf.ioc_up = (void *) &quotabuf;
1594 quotabuf.cmd = VX_GETQUOTA;
1595 quotabuf.uid = euser_id;
1596 quotabuf.addr = (caddr_t) &D;
1597 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1598 close(file);
1600 set_effective_uid(euser_id);
1602 if (ret < 0) {
1603 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1604 return(False);
1607 /* If softlimit is zero, set it equal to hardlimit.
1610 if (D.dqb_bsoftlimit==0)
1611 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1613 /* Use softlimit to determine disk space. A user exceeding the quota is told
1614 * that there's no space left. Writes might actually work for a bit if the
1615 * hardlimit is set higher than softlimit. Effectively the disk becomes
1616 * made of rubber latex and begins to expand to accommodate the user :-)
1618 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1619 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1620 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1622 if (D.dqb_bsoftlimit==0)
1623 return(False);
1624 *bsize = DEV_BSIZE;
1625 *dsize = D.dqb_bsoftlimit;
1627 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1628 *dfree = 0;
1629 *dsize = D.dqb_curblocks;
1630 } else
1631 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1633 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1634 path,(double)*bsize,(double)*dfree,(double)*dsize));
1636 return(True);
1639 #endif /* SUNOS5 || ... */
1641 #endif /* VXFS_QUOTA */
1643 #else /* WITH_QUOTAS */
1645 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1647 (*bsize) = 512; /* This value should be ignored */
1649 /* And just to be sure we set some values that hopefully */
1650 /* will be larger that any possible real-world value */
1651 (*dfree) = (uint64_t)-1;
1652 (*dsize) = (uint64_t)-1;
1654 /* As we have select not to use quotas, allways fail */
1655 return false;
1657 #endif /* WITH_QUOTAS */
1659 #else /* HAVE_SYS_QUOTAS */
1660 /* wrapper to the new sys_quota interface
1661 this file should be removed later
1663 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1665 int r;
1666 SMB_DISK_QUOTA D;
1667 unid_t id;
1669 id.uid = geteuid();
1671 ZERO_STRUCT(D);
1672 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1674 /* Use softlimit to determine disk space, except when it has been exceeded */
1675 *bsize = D.bsize;
1676 if (r == -1) {
1677 if (errno == EDQUOT) {
1678 *dfree =0;
1679 *dsize =D.curblocks;
1680 return (True);
1681 } else {
1682 goto try_group_quota;
1686 /* Use softlimit to determine disk space, except when it has been exceeded */
1687 if (
1688 (D.softlimit && D.curblocks >= D.softlimit) ||
1689 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1690 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1691 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1693 *dfree = 0;
1694 *dsize = D.curblocks;
1695 } else if (D.softlimit==0 && D.hardlimit==0) {
1696 goto try_group_quota;
1697 } else {
1698 if (D.softlimit == 0)
1699 D.softlimit = D.hardlimit;
1700 *dfree = D.softlimit - D.curblocks;
1701 *dsize = D.softlimit;
1704 return True;
1706 try_group_quota:
1707 id.gid = getegid();
1709 ZERO_STRUCT(D);
1710 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1712 /* Use softlimit to determine disk space, except when it has been exceeded */
1713 *bsize = D.bsize;
1714 if (r == -1) {
1715 if (errno == EDQUOT) {
1716 *dfree =0;
1717 *dsize =D.curblocks;
1718 return (True);
1719 } else {
1720 return False;
1724 /* Use softlimit to determine disk space, except when it has been exceeded */
1725 if (
1726 (D.softlimit && D.curblocks >= D.softlimit) ||
1727 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1728 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1729 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1731 *dfree = 0;
1732 *dsize = D.curblocks;
1733 } else if (D.softlimit==0 && D.hardlimit==0) {
1734 return False;
1735 } else {
1736 if (D.softlimit == 0)
1737 D.softlimit = D.hardlimit;
1738 *dfree = D.softlimit - D.curblocks;
1739 *dsize = D.softlimit;
1742 return (True);
1744 #endif /* HAVE_SYS_QUOTAS */