s3-printing: Restrict printing=cups to systems with cups development headers at build...
[Samba/bb.git] / source3 / smbd / quotas.c
blobd8bdb0225ca0296927bd29da7290fc68f62c11f9
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"
29 #include "system/filesys.h"
31 #undef DBGC_CLASS
32 #define DBGC_CLASS DBGC_QUOTA
34 #ifndef HAVE_SYS_QUOTAS
36 /* just a quick hack because sysquotas.h is included before linux/quota.h */
37 #ifdef QUOTABLOCK_SIZE
38 #undef QUOTABLOCK_SIZE
39 #endif
41 #ifdef WITH_QUOTAS
43 #if defined(VXFS_QUOTA)
46 * In addition to their native filesystems, some systems have Veritas VxFS.
47 * Declare here, define at end: reduces likely "include" interaction problems.
48 * David Lee <T.D.Lee@durham.ac.uk>
50 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
52 #endif /* VXFS_QUOTA */
55 #ifdef LINUX
57 #include <sys/types.h>
58 #include <mntent.h>
61 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
62 * So we include all the files has *should* be in the system into a large,
63 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
66 #include "samba_linux_quota.h"
68 typedef struct _LINUX_SMB_DISK_QUOTA {
69 uint64_t bsize;
70 uint64_t hardlimit; /* In bsize units. */
71 uint64_t softlimit; /* In bsize units. */
72 uint64_t curblocks; /* In bsize units. */
73 uint64_t ihardlimit; /* inode hard limit. */
74 uint64_t isoftlimit; /* inode soft limit. */
75 uint64_t curinodes; /* Current used inodes. */
76 } LINUX_SMB_DISK_QUOTA;
80 * nfs quota support
81 * (essentially taken from FreeBSD / SUNOS5 section)
83 #include <rpc/rpc.h>
84 #include <rpc/types.h>
85 #include <rpcsvc/rquota.h>
86 #ifdef HAVE_RPC_NETTYPE_H
87 #include <rpc/nettype.h>
88 #endif
89 #include <rpc/xdr.h>
91 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
93 int quotastat;
95 if (!xdr_int(xdrsp, &quotastat)) {
96 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
97 return 0;
99 gqr->status = quotastat;
101 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
102 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
103 return 0;
105 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
106 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
107 return 0;
109 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
110 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
111 return 0;
113 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
114 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
115 return 0;
117 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
118 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
119 return 0;
121 return 1;
124 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize,
125 uint64_t *dfree, uint64_t *dsize)
127 uid_t uid = euser_id;
128 LINUX_SMB_DISK_QUOTA D;
129 char *mnttype = nfspath;
130 CLIENT *clnt;
131 struct getquota_rslt gqr;
132 struct getquota_args args;
133 char *cutstr, *pathname, *host, *testpath;
134 int len;
135 static struct timeval timeout = {2,0};
136 enum clnt_stat clnt_stat;
137 bool ret = True;
139 *bsize = *dfree = *dsize = (uint64_t)0;
141 len=strcspn(mnttype, ":");
142 pathname=strstr(mnttype, ":");
143 cutstr = (char *) SMB_MALLOC(len+1);
144 if (!cutstr)
145 return False;
147 memset(cutstr, '\0', len+1);
148 host = strncat(cutstr,mnttype, sizeof(char) * len );
149 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
150 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
151 testpath=strchr_m(mnttype, ':');
152 args.gqa_pathp = testpath+1;
153 args.gqa_uid = uid;
155 DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers "
156 "\"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS,
157 "udp"));
159 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
160 ret = False;
161 goto out;
164 clnt->cl_auth = authunix_create_default();
165 DEBUG(9,("nfs_quotas: auth_success\n"));
167 clnt_stat=clnt_call(clnt,
168 RQUOTAPROC_GETQUOTA,
169 (const xdrproc_t)my_xdr_getquota_args,
170 (caddr_t)&args,
171 (const xdrproc_t)my_xdr_getquota_rslt,
172 (caddr_t)&gqr, timeout);
174 if (clnt_stat != RPC_SUCCESS) {
175 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
176 ret = False;
177 goto out;
181 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
182 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
183 * something sensible.
186 switch (gqr.status) {
187 case 0:
188 DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n",
189 gqr.status));
190 ret = False;
191 goto out;
193 case 1:
194 DEBUG(9,("nfs_quotas: Good quota data\n"));
195 D.softlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
196 D.hardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
197 D.curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
198 break;
200 case 2:
201 case 3:
202 D.softlimit = 1;
203 D.curblocks = 1;
204 DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n",
205 gqr.status));
206 break;
208 default:
209 DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! "
210 "Error \"%i\" \n", gqr.status));
211 break;
214 DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... "
215 "status \"%i\" bsize \"%i\" active? \"%i\" bhard "
216 "\"%i\" bsoft \"%i\" curb \"%i\" \n",
217 gqr.status,
218 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
219 gqr.getquota_rslt_u.gqr_rquota.rq_active,
220 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
221 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
222 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
224 if (D.softlimit == 0)
225 D.softlimit = D.hardlimit;
226 if (D.softlimit == 0)
227 return False;
229 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
230 *dsize = D.softlimit;
232 if (D.curblocks == 1)
233 *bsize = DEV_BSIZE;
235 if (D.curblocks > D.softlimit) {
236 *dfree = 0;
237 *dsize = D.curblocks;
238 } else
239 *dfree = D.softlimit - D.curblocks;
241 out:
243 if (clnt) {
244 if (clnt->cl_auth)
245 auth_destroy(clnt->cl_auth);
246 clnt_destroy(clnt);
249 DEBUG(5, ("nfs_quotas: For path \"%s\" returning "
250 "bsize %.0f, dfree %.0f, dsize %.0f\n",
251 args.gqa_pathp, (double)*bsize, (double)*dfree,
252 (double)*dsize));
254 SAFE_FREE(cutstr);
255 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
256 return ret;
259 /* end of nfs quota section */
261 #ifdef HAVE_LINUX_DQBLK_XFS_H
262 #include <linux/dqblk_xfs.h>
264 /****************************************************************************
265 Abstract out the XFS Quota Manager quota get call.
266 ****************************************************************************/
268 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
270 struct fs_disk_quota D;
271 int ret;
273 ZERO_STRUCT(D);
275 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
277 if (ret)
278 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
280 if (ret)
281 return ret;
283 dp->bsize = (uint64_t)512;
284 dp->softlimit = (uint64_t)D.d_blk_softlimit;
285 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
286 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
287 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
288 dp->curinodes = (uint64_t)D.d_icount;
289 dp->curblocks = (uint64_t)D.d_bcount;
291 return ret;
293 #else
294 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
296 DEBUG(0,("XFS quota support not available\n"));
297 errno = ENOSYS;
298 return -1;
300 #endif
303 /****************************************************************************
304 Abstract out the old and new Linux quota get calls.
305 ****************************************************************************/
307 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
309 struct v1_kern_dqblk D;
310 int ret;
312 ZERO_STRUCT(D);
314 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
316 if (ret && errno != EDQUOT)
317 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
319 if (ret && errno != EDQUOT)
320 return ret;
322 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
323 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
324 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
325 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
326 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
327 dp->curinodes = (uint64_t)D.dqb_curinodes;
328 dp->curblocks = (uint64_t)D.dqb_curblocks;
330 return ret;
333 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
335 struct v2_kern_dqblk D;
336 int ret;
338 ZERO_STRUCT(D);
340 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
342 if (ret && errno != EDQUOT)
343 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
345 if (ret && errno != EDQUOT)
346 return ret;
348 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
349 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
350 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
351 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
352 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
353 dp->curinodes = (uint64_t)D.dqb_curinodes;
354 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
356 return ret;
359 /****************************************************************************
360 Brand-new generic quota interface.
361 ****************************************************************************/
363 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
365 struct if_dqblk D;
366 int ret;
368 ZERO_STRUCT(D);
370 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
372 if (ret && errno != EDQUOT)
373 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
375 if (ret && errno != EDQUOT)
376 return ret;
378 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
379 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
380 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
381 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
382 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
383 dp->curinodes = (uint64_t)D.dqb_curinodes;
384 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
386 return ret;
389 /****************************************************************************
390 Try to get the disk space from disk quotas (LINUX version).
391 ****************************************************************************/
393 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
395 int r;
396 SMB_STRUCT_STAT S;
397 FILE *fp;
398 LINUX_SMB_DISK_QUOTA D;
399 struct mntent *mnt;
400 SMB_DEV_T devno;
401 int found;
402 uid_t euser_id;
403 gid_t egrp_id;
405 ZERO_STRUCT(D);
407 euser_id = geteuid();
408 egrp_id = getegid();
410 /* find the block device file */
412 if (sys_stat(path, &S, false) == -1 )
413 return(False) ;
415 devno = S.st_ex_dev ;
417 if ((fp = setmntent(MOUNTED,"r")) == NULL)
418 return(False) ;
420 found = False ;
422 while ((mnt = getmntent(fp))) {
423 if (sys_stat(mnt->mnt_dir, &S, false) == -1)
424 continue ;
426 if (S.st_ex_dev == devno) {
427 found = True ;
428 break;
432 endmntent(fp) ;
434 if (!found)
435 return(False);
437 become_root();
439 if (strcmp(mnt->mnt_type, "nfs") == 0) {
440 bool retval;
441 retval = nfs_quotas(mnt->mnt_fsname , euser_id, bsize, dfree, dsize);
442 unbecome_root();
443 return retval;
446 if (strcmp(mnt->mnt_type, "xfs")==0) {
447 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
448 } else {
449 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
450 if (r == -1 && errno != EDQUOT) {
451 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
452 if (r == -1 && errno != EDQUOT)
453 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
457 unbecome_root();
459 /* Use softlimit to determine disk space, except when it has been exceeded */
460 *bsize = D.bsize;
461 if (r == -1) {
462 if (errno == EDQUOT) {
463 *dfree =0;
464 *dsize =D.curblocks;
465 return (True);
466 } else {
467 return(False);
471 /* Use softlimit to determine disk space, except when it has been exceeded */
472 if (
473 (D.softlimit && D.curblocks >= D.softlimit) ||
474 (D.hardlimit && D.curblocks >= D.hardlimit) ||
475 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
476 (D.ihardlimit && D.curinodes>=D.ihardlimit)
478 *dfree = 0;
479 *dsize = D.curblocks;
480 } else if (D.softlimit==0 && D.hardlimit==0) {
481 return(False);
482 } else {
483 if (D.softlimit == 0)
484 D.softlimit = D.hardlimit;
485 *dfree = D.softlimit - D.curblocks;
486 *dsize = D.softlimit;
489 return (True);
492 #elif defined(CRAY)
494 #include <sys/quota.h>
495 #include <mntent.h>
497 /****************************************************************************
498 try to get the disk space from disk quotas (CRAY VERSION)
499 ****************************************************************************/
501 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
503 struct mntent *mnt;
504 FILE *fd;
505 SMB_STRUCT_STAT sbuf;
506 SMB_DEV_T devno ;
507 struct q_request request ;
508 struct qf_header header ;
509 int quota_default = 0 ;
510 bool found = false;
512 if (sys_stat(path, &sbuf, false) == -1) {
513 return false;
516 devno = sbuf.st_ex_dev ;
518 if ((fd = setmntent(KMTAB)) == NULL) {
519 return false;
522 while ((mnt = getmntent(fd)) != NULL) {
523 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
524 continue;
526 if (sbuf.st_ex_dev == devno) {
527 found = frue ;
528 break;
532 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
533 endmntent(fd);
534 if (!found) {
535 return false;
538 if (!name) {
539 return false;
542 request.qf_magic = QF_MAGIC ;
543 request.qf_entry.id = geteuid() ;
545 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
546 return false;
549 if (!request.user) {
550 return False;
553 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
554 if (!quota_default) {
555 if (quotactl(name, Q_GETHEADER, &header) == -1) {
556 return false;
557 } else {
558 quota_default = header.user_h.def_fq;
561 *dfree = quota_default;
562 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
563 *dfree = 0;
564 } else {
565 *dfree = request.qf_entry.user_q.f_quota;
568 *dsize = request.qf_entry.user_q.f_use;
570 if (*dfree < *dsize) {
571 *dfree = 0;
572 } else {
573 *dfree -= *dsize;
576 *bsize = 4096 ; /* Cray blocksize */
577 return true;
581 #elif defined(SUNOS5) || defined(SUNOS4)
583 #include <fcntl.h>
584 #include <sys/param.h>
585 #if defined(SUNOS5)
586 #include <sys/fs/ufs_quota.h>
587 #include <sys/mnttab.h>
588 #include <sys/mntent.h>
589 #else /* defined(SUNOS4) */
590 #include <ufs/quota.h>
591 #include <mntent.h>
592 #endif
594 #if defined(SUNOS5)
596 /****************************************************************************
597 Allows querying of remote hosts for quotas on NFS mounted shares.
598 Supports normal NFS and AMD mounts.
599 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
600 ****************************************************************************/
602 #include <rpc/rpc.h>
603 #include <rpc/types.h>
604 #include <rpcsvc/rquota.h>
605 #include <rpc/nettype.h>
606 #include <rpc/xdr.h>
608 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
610 int quotastat;
612 if (!xdr_int(xdrsp, &quotastat)) {
613 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
614 return 0;
616 gqr->status = quotastat;
618 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
619 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
620 return 0;
622 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
623 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
624 return 0;
626 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
627 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
628 return 0;
630 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
631 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
632 return 0;
634 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
635 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
636 return 0;
638 return (1);
641 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
642 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
644 uid_t uid = euser_id;
645 struct dqblk D;
646 char *mnttype = nfspath;
647 CLIENT *clnt;
648 struct getquota_rslt gqr;
649 struct getquota_args args;
650 char *cutstr, *pathname, *host, *testpath;
651 int len;
652 static struct timeval timeout = {2,0};
653 enum clnt_stat clnt_stat;
654 bool ret = True;
656 *bsize = *dfree = *dsize = (uint64_t)0;
658 len=strcspn(mnttype, ":");
659 pathname=strstr(mnttype, ":");
660 cutstr = (char *) SMB_MALLOC(len+1);
661 if (!cutstr)
662 return False;
664 memset(cutstr, '\0', len+1);
665 host = strncat(cutstr,mnttype, sizeof(char) * len );
666 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
667 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
668 testpath=strchr_m(mnttype, ':');
669 args.gqa_pathp = testpath+1;
670 args.gqa_uid = uid;
672 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
674 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
675 ret = False;
676 goto out;
679 clnt->cl_auth = authunix_create_default();
680 DEBUG(9,("nfs_quotas: auth_success\n"));
682 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
684 if (clnt_stat != RPC_SUCCESS) {
685 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
686 ret = False;
687 goto out;
691 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
692 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
693 * something sensible.
696 switch (gqr.status) {
697 case 0:
698 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
699 ret = False;
700 goto out;
702 case 1:
703 DEBUG(9,("nfs_quotas: Good quota data\n"));
704 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
705 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
706 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
707 break;
709 case 2:
710 case 3:
711 D.dqb_bsoftlimit = 1;
712 D.dqb_curblocks = 1;
713 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
714 break;
716 default:
717 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
718 break;
721 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",
722 gqr.status,
723 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
724 gqr.getquota_rslt_u.gqr_rquota.rq_active,
725 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
726 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
727 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
729 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
730 *dsize = D.dqb_bsoftlimit;
732 if (D.dqb_curblocks == 1)
733 *bsize = 512;
735 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
736 *dfree = 0;
737 *dsize = D.dqb_curblocks;
738 } else
739 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
741 out:
743 if (clnt) {
744 if (clnt->cl_auth)
745 auth_destroy(clnt->cl_auth);
746 clnt_destroy(clnt);
749 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
751 SAFE_FREE(cutstr);
752 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
753 return ret;
755 #endif
757 /****************************************************************************
758 try to get the disk space from disk quotas (SunOS & Solaris2 version)
759 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
760 ****************************************************************************/
762 bool disk_quotas(const char *path,
763 uint64_t *bsize,
764 uint64_t *dfree,
765 uint64_t *dsize)
767 uid_t euser_id;
768 int ret;
769 struct dqblk D;
770 #if defined(SUNOS5)
771 struct quotctl command;
772 int file;
773 struct mnttab mnt;
774 #else /* SunOS4 */
775 struct mntent *mnt;
776 #endif
777 char *name = NULL;
778 FILE *fd;
779 SMB_STRUCT_STAT sbuf;
780 SMB_DEV_T devno;
781 bool found = false;
783 euser_id = geteuid();
785 if (sys_stat(path, &sbuf, false) == -1) {
786 return false;
789 devno = sbuf.st_ex_dev ;
790 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
791 path, (unsigned int)devno));
792 #if defined(SUNOS5)
793 if ((fd = fopen(MNTTAB, "r")) == NULL) {
794 return false;
797 while (getmntent(fd, &mnt) == 0) {
798 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
799 continue;
802 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
803 mnt.mnt_mountp, (unsigned int)devno));
805 /* quotas are only on vxfs, UFS or NFS */
806 if ((sbuf.st_ex_dev == devno) && (
807 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
808 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
809 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
810 found = true;
811 name = talloc_asprintf(talloc_tos(),
812 "%s/quotas",
813 mnt.mnt_mountp);
814 break;
818 fclose(fd);
819 #else /* SunOS4 */
820 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
821 return false;
824 while ((mnt = getmntent(fd)) != NULL) {
825 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
826 continue;
828 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
829 mnt->mnt_dir,
830 (unsigned int)sbuf.st_ex_dev));
831 if (sbuf.st_ex_dev == devno) {
832 found = true;
833 name = talloc_strdup(talloc_tos(),
834 mnt->mnt_fsname);
835 break;
839 endmntent(fd);
840 #endif
841 if (!found) {
842 return false;
845 if (!name) {
846 return false;
848 become_root();
850 #if defined(SUNOS5)
851 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
852 bool retval;
853 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
854 mnt.mnt_special));
855 retval = nfs_quotas(mnt.mnt_special,
856 euser_id, bsize, dfree, dsize);
857 unbecome_root();
858 return retval;
861 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
862 if((file=open(name, O_RDONLY,0))<0) {
863 unbecome_root();
864 return false;
866 command.op = Q_GETQUOTA;
867 command.uid = euser_id;
868 command.addr = (caddr_t) &D;
869 ret = ioctl(file, Q_QUOTACTL, &command);
870 close(file);
871 #else
872 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
873 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
874 #endif
876 unbecome_root();
878 if (ret < 0) {
879 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
880 strerror(errno) ));
882 #if defined(SUNOS5) && defined(VXFS_QUOTA)
883 /* If normal quotactl() fails, try vxfs private calls */
884 set_effective_uid(euser_id);
885 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
886 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
887 bool retval;
888 retval = disk_quotas_vxfs(name, path,
889 bsize, dfree, dsize);
890 return retval;
892 #else
893 return false;
894 #endif
897 /* If softlimit is zero, set it equal to hardlimit.
900 if (D.dqb_bsoftlimit==0) {
901 D.dqb_bsoftlimit = D.dqb_bhardlimit;
904 /* Use softlimit to determine disk space. A user exceeding the quota
905 * is told that there's no space left. Writes might actually work for
906 * a bit if the hardlimit is set higher than softlimit. Effectively
907 * the disk becomes made of rubber latex and begins to expand to
908 * accommodate the user :-)
911 if (D.dqb_bsoftlimit==0)
912 return(False);
913 *bsize = DEV_BSIZE;
914 *dsize = D.dqb_bsoftlimit;
916 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
917 *dfree = 0;
918 *dsize = D.dqb_curblocks;
919 } else {
920 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
923 DEBUG(5,("disk_quotas for path \"%s\" returning "
924 "bsize %.0f, dfree %.0f, dsize %.0f\n",
925 path,(double)*bsize,(double)*dfree,(double)*dsize));
927 return true;
931 #elif defined(OSF1)
932 #include <ufs/quota.h>
934 /****************************************************************************
935 try to get the disk space from disk quotas - OSF1 version
936 ****************************************************************************/
938 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
940 int r, save_errno;
941 struct dqblk D;
942 SMB_STRUCT_STAT S;
943 uid_t euser_id;
946 * This code presumes that OSF1 will only
947 * give out quota info when the real uid
948 * matches the effective uid. JRA.
950 euser_id = geteuid();
951 save_re_uid();
952 if (set_re_uid() != 0) return False;
954 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
955 if (r) {
956 save_errno = errno;
959 restore_re_uid();
961 *bsize = DEV_BSIZE;
963 if (r)
965 if (save_errno == EDQUOT) /* disk quota exceeded */
967 *dfree = 0;
968 *dsize = D.dqb_curblocks;
969 return (True);
971 else
972 return (False);
975 /* If softlimit is zero, set it equal to hardlimit.
978 if (D.dqb_bsoftlimit==0)
979 D.dqb_bsoftlimit = D.dqb_bhardlimit;
981 /* Use softlimit to determine disk space, except when it has been exceeded */
983 if (D.dqb_bsoftlimit==0)
984 return(False);
986 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
987 *dfree = 0;
988 *dsize = D.dqb_curblocks;
989 } else {
990 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
991 *dsize = D.dqb_bsoftlimit;
993 return (True);
996 #elif defined (IRIX6)
997 /****************************************************************************
998 try to get the disk space from disk quotas (IRIX 6.2 version)
999 ****************************************************************************/
1001 #include <sys/quota.h>
1002 #include <mntent.h>
1004 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1006 uid_t euser_id;
1007 int r;
1008 struct dqblk D;
1009 struct fs_disk_quota F;
1010 SMB_STRUCT_STAT S;
1011 FILE *fp;
1012 struct mntent *mnt;
1013 SMB_DEV_T devno;
1014 int found;
1016 /* find the block device file */
1018 if ( sys_stat(path, &S, false) == -1 ) {
1019 return(False) ;
1022 devno = S.st_ex_dev ;
1024 fp = setmntent(MOUNTED,"r");
1025 found = False ;
1027 while ((mnt = getmntent(fp))) {
1028 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
1029 continue ;
1030 if (S.st_ex_dev == devno) {
1031 found = True ;
1032 break ;
1035 endmntent(fp) ;
1037 if (!found) {
1038 return(False);
1041 euser_id=geteuid();
1042 become_root();
1044 /* Use softlimit to determine disk space, except when it has been exceeded */
1046 *bsize = 512;
1048 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
1050 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
1052 unbecome_root();
1054 if (r==-1)
1055 return(False);
1057 /* Use softlimit to determine disk space, except when it has been exceeded */
1058 if (
1059 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
1060 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
1061 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
1062 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
1065 *dfree = 0;
1066 *dsize = D.dqb_curblocks;
1068 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
1070 return(False);
1072 else
1074 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1075 *dsize = D.dqb_bsoftlimit;
1079 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
1081 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
1083 unbecome_root();
1085 if (r==-1)
1087 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
1088 return(False);
1091 /* No quota for this user. */
1092 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1094 return(False);
1097 /* Use softlimit to determine disk space, except when it has been exceeded */
1098 if (
1099 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1100 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1101 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1102 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1105 *dfree = 0;
1106 *dsize = F.d_bcount;
1108 else
1110 *dfree = (F.d_blk_softlimit - F.d_bcount);
1111 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1115 else
1117 unbecome_root();
1118 return(False);
1121 return (True);
1125 #else
1127 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1128 #include <ufs/ufs/quota.h>
1129 #include <machine/param.h>
1130 #elif AIX
1131 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1132 #include <jfs/quota.h>
1133 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1134 #define dqb_curfiles dqb_curinodes
1135 #define dqb_fhardlimit dqb_ihardlimit
1136 #define dqb_fsoftlimit dqb_isoftlimit
1137 #ifdef _AIXVERSION_530
1138 #include <sys/statfs.h>
1139 #include <sys/vmount.h>
1140 #endif /* AIX 5.3 */
1141 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1142 #include <sys/quota.h>
1143 #include <devnm.h>
1144 #endif
1146 #if defined(__FreeBSD__) || defined(__DragonFly__)
1148 #include <rpc/rpc.h>
1149 #include <rpc/types.h>
1150 #include <rpcsvc/rquota.h>
1151 #ifdef HAVE_RPC_NETTYPE_H
1152 #include <rpc/nettype.h>
1153 #endif
1154 #include <rpc/xdr.h>
1156 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1158 int quotastat;
1160 if (!xdr_int(xdrsp, &quotastat)) {
1161 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1162 return 0;
1164 gqr->status = quotastat;
1166 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1167 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1168 return 0;
1170 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1171 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1172 return 0;
1174 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1175 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1176 return 0;
1178 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1179 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1180 return 0;
1182 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1183 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1184 return 0;
1186 return (1);
1189 /* Works on FreeBSD, too. :-) */
1190 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1192 uid_t uid = euser_id;
1193 struct dqblk D;
1194 char *mnttype = nfspath;
1195 CLIENT *clnt;
1196 struct getquota_rslt gqr;
1197 struct getquota_args args;
1198 char *cutstr, *pathname, *host, *testpath;
1199 int len;
1200 static struct timeval timeout = {2,0};
1201 enum clnt_stat clnt_stat;
1202 bool ret = True;
1204 *bsize = *dfree = *dsize = (uint64_t)0;
1206 len=strcspn(mnttype, ":");
1207 pathname=strstr(mnttype, ":");
1208 cutstr = (char *) SMB_MALLOC(len+1);
1209 if (!cutstr)
1210 return False;
1212 memset(cutstr, '\0', len+1);
1213 host = strncat(cutstr,mnttype, sizeof(char) * len );
1214 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1215 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1216 testpath=strchr_m(mnttype, ':');
1217 args.gqa_pathp = testpath+1;
1218 args.gqa_uid = uid;
1220 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1222 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1223 ret = False;
1224 goto out;
1227 clnt->cl_auth = authunix_create_default();
1228 DEBUG(9,("nfs_quotas: auth_success\n"));
1230 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);
1232 if (clnt_stat != RPC_SUCCESS) {
1233 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1234 ret = False;
1235 goto out;
1239 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1240 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1241 * something sensible.
1244 switch (gqr.status) {
1245 case 0:
1246 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1247 ret = False;
1248 goto out;
1250 case 1:
1251 DEBUG(9,("nfs_quotas: Good quota data\n"));
1252 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1253 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1254 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1255 break;
1257 case 2:
1258 case 3:
1259 D.dqb_bsoftlimit = 1;
1260 D.dqb_curblocks = 1;
1261 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1262 break;
1264 default:
1265 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1266 break;
1269 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",
1270 gqr.status,
1271 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1272 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1273 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1274 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1275 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1277 if (D.dqb_bsoftlimit == 0)
1278 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1279 if (D.dqb_bsoftlimit == 0)
1280 return False;
1282 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1283 *dsize = D.dqb_bsoftlimit;
1285 if (D.dqb_curblocks == 1)
1286 *bsize = DEV_BSIZE;
1288 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1289 *dfree = 0;
1290 *dsize = D.dqb_curblocks;
1291 } else
1292 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1294 out:
1296 if (clnt) {
1297 if (clnt->cl_auth)
1298 auth_destroy(clnt->cl_auth);
1299 clnt_destroy(clnt);
1302 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1304 SAFE_FREE(cutstr);
1305 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1306 return ret;
1309 #endif
1311 /****************************************************************************
1312 try to get the disk space from disk quotas - default version
1313 ****************************************************************************/
1315 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1317 int r;
1318 struct dqblk D;
1319 uid_t euser_id;
1320 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1321 char dev_disk[256];
1322 SMB_STRUCT_STAT S;
1324 /* find the block device file */
1326 #ifdef HPUX
1327 /* Need to set the cache flag to 1 for HPUX. Seems
1328 * to have a significant performance boost when
1329 * lstat calls on /dev access this function.
1331 if ((sys_stat(path, &S, false)<0)
1332 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1333 #else
1334 if ((sys_stat(path, &S, false)<0)
1335 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1336 return (False);
1337 #endif /* ifdef HPUX */
1339 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1341 euser_id = geteuid();
1343 #ifdef HPUX
1344 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1345 save_re_uid();
1346 if (set_re_uid() != 0) return False;
1348 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1350 restore_re_uid();
1351 #else
1352 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1354 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1355 gid_t egrp_id;
1356 #if defined(__FreeBSD__) || defined(__DragonFly__)
1357 SMB_DEV_T devno;
1358 struct statfs *mnts;
1359 SMB_STRUCT_STAT st;
1360 int mntsize, i;
1362 if (sys_stat(path, &st, false) < 0)
1363 return False;
1364 devno = st.st_ex_dev;
1366 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1367 if (mntsize <= 0)
1368 return False;
1370 for (i = 0; i < mntsize; i++) {
1371 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1372 return False;
1373 if (st.st_ex_dev == devno)
1374 break;
1376 if (i == mntsize)
1377 return False;
1378 #endif
1380 become_root();
1382 #if defined(__FreeBSD__) || defined(__DragonFly__)
1383 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1384 bool retval;
1385 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1386 unbecome_root();
1387 return retval;
1389 #endif
1391 egrp_id = getegid();
1392 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1394 /* As FreeBSD has group quotas, if getting the user
1395 quota fails, try getting the group instead. */
1396 if (r) {
1397 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1400 unbecome_root();
1402 #elif defined(AIX)
1403 /* AIX has both USER and GROUP quotas:
1404 Get the USER quota (ohnielse@fysik.dtu.dk) */
1405 #ifdef _AIXVERSION_530
1407 struct statfs statbuf;
1408 quota64_t user_quota;
1409 if (statfs(path,&statbuf) != 0)
1410 return False;
1411 if(statbuf.f_vfstype == MNT_J2)
1413 /* For some reason we need to be root for jfs2 */
1414 become_root();
1415 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1416 unbecome_root();
1417 /* Copy results to old struct to let the following code work as before */
1418 D.dqb_curblocks = user_quota.bused;
1419 D.dqb_bsoftlimit = user_quota.bsoft;
1420 D.dqb_bhardlimit = user_quota.bhard;
1421 D.dqb_curfiles = user_quota.iused;
1422 D.dqb_fsoftlimit = user_quota.isoft;
1423 D.dqb_fhardlimit = user_quota.ihard;
1425 else if(statbuf.f_vfstype == MNT_JFS)
1427 #endif /* AIX 5.3 */
1428 save_re_uid();
1429 if (set_re_uid() != 0)
1430 return False;
1431 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1432 restore_re_uid();
1433 #ifdef _AIXVERSION_530
1435 else
1436 r = 1; /* Fail for other FS-types */
1438 #endif /* AIX 5.3 */
1439 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1440 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1441 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1442 #endif /* HPUX */
1444 /* Use softlimit to determine disk space, except when it has been exceeded */
1445 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1446 *bsize = DEV_BSIZE;
1447 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1448 *bsize = 1024;
1449 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1451 if (r)
1453 if (errno == EDQUOT)
1455 *dfree =0;
1456 *dsize =D.dqb_curblocks;
1457 return (True);
1459 else return(False);
1462 /* If softlimit is zero, set it equal to hardlimit.
1465 if (D.dqb_bsoftlimit==0)
1466 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1468 if (D.dqb_bsoftlimit==0)
1469 return(False);
1470 /* Use softlimit to determine disk space, except when it has been exceeded */
1471 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1472 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1473 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1474 #endif
1476 *dfree = 0;
1477 *dsize = D.dqb_curblocks;
1479 else {
1480 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1481 *dsize = D.dqb_bsoftlimit;
1483 return (True);
1486 #endif
1488 #if definedr(LINUX) || defined(SUNOS) || defined (__FreeBSD__) || defined(__DragonFly__)
1489 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1491 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1492 return(0);
1493 if (!xdr_int(xdrsp, &args->gqa_uid))
1494 return(0);
1495 return (1);
1497 #endif
1499 #if defined(VXFS_QUOTA)
1501 /****************************************************************************
1502 Try to get the disk space from Veritas disk quotas.
1503 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1505 Background assumptions:
1506 Potentially under many Operating Systems. Initially Solaris 2.
1508 My guess is that Veritas is largely, though not entirely,
1509 independent of OS. So I have separated it out.
1511 There may be some details. For example, OS-specific "include" files.
1513 It is understood that HPUX 10 somehow gets Veritas quotas without
1514 any special effort; if so, this routine need not be compiled in.
1515 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1517 Warning:
1518 It is understood that Veritas do not publicly support this ioctl interface.
1519 Rather their preference would be for the user (us) to call the native
1520 OS and then for the OS itself to call through to the VxFS filesystem.
1521 Presumably HPUX 10, see above, does this.
1523 Hints for porting:
1524 Add your OS to "IFLIST" below.
1525 Get it to compile successfully:
1526 Almost certainly "include"s require attention: see SUNOS5.
1527 In the main code above, arrange for it to be called: see SUNOS5.
1528 Test!
1530 ****************************************************************************/
1532 /* "IFLIST"
1533 * This "if" is a list of ports:
1534 * if defined(OS1) || defined(OS2) || ...
1536 #if defined(SUNOS5)
1538 #if defined(SUNOS5)
1539 #include <sys/fs/vx_solaris.h>
1540 #endif
1541 #include <sys/fs/vx_machdep.h>
1542 #include <sys/fs/vx_layout.h>
1543 #include <sys/fs/vx_quota.h>
1544 #include <sys/fs/vx_aioctl.h>
1545 #include <sys/fs/vx_ioctl.h>
1547 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1549 uid_t user_id, euser_id;
1550 int ret;
1551 struct vx_dqblk D;
1552 struct vx_quotctl quotabuf;
1553 struct vx_genioctl genbuf;
1554 char *qfname;
1555 int file;
1558 * "name" may or may not include a trailing "/quotas".
1559 * Arranging consistency of calling here in "quotas.c" may not be easy and
1560 * it might be easier to examine and adjust it here.
1561 * Fortunately, VxFS seems not to mind at present.
1563 qfname = talloc_strdup(talloc_tos(), name);
1564 if (!qfname) {
1565 return false;
1567 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1569 euser_id = geteuid();
1570 set_effective_uid(0);
1572 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1573 if((file=open(qfname, O_RDONLY,0))<0) {
1574 set_effective_uid(euser_id);
1575 return(False);
1577 genbuf.ioc_cmd = VX_QUOTACTL;
1578 genbuf.ioc_up = (void *) &quotabuf;
1580 quotabuf.cmd = VX_GETQUOTA;
1581 quotabuf.uid = euser_id;
1582 quotabuf.addr = (caddr_t) &D;
1583 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1584 close(file);
1586 set_effective_uid(euser_id);
1588 if (ret < 0) {
1589 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1590 return(False);
1593 /* If softlimit is zero, set it equal to hardlimit.
1596 if (D.dqb_bsoftlimit==0)
1597 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1599 /* Use softlimit to determine disk space. A user exceeding the quota is told
1600 * that there's no space left. Writes might actually work for a bit if the
1601 * hardlimit is set higher than softlimit. Effectively the disk becomes
1602 * made of rubber latex and begins to expand to accommodate the user :-)
1604 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1605 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1606 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1608 if (D.dqb_bsoftlimit==0)
1609 return(False);
1610 *bsize = DEV_BSIZE;
1611 *dsize = D.dqb_bsoftlimit;
1613 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1614 *dfree = 0;
1615 *dsize = D.dqb_curblocks;
1616 } else
1617 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1619 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1620 path,(double)*bsize,(double)*dfree,(double)*dsize));
1622 return(True);
1625 #endif /* SUNOS5 || ... */
1627 #endif /* VXFS_QUOTA */
1629 #else /* WITH_QUOTAS */
1631 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1633 (*bsize) = 512; /* This value should be ignored */
1635 /* And just to be sure we set some values that hopefully */
1636 /* will be larger that any possible real-world value */
1637 (*dfree) = (uint64_t)-1;
1638 (*dsize) = (uint64_t)-1;
1640 /* As we have select not to use quotas, allways fail */
1641 return false;
1643 #endif /* WITH_QUOTAS */
1645 #else /* HAVE_SYS_QUOTAS */
1646 /* wrapper to the new sys_quota interface
1647 this file should be removed later
1649 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1651 int r;
1652 SMB_DISK_QUOTA D;
1653 unid_t id;
1655 id.uid = geteuid();
1657 ZERO_STRUCT(D);
1658 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1660 /* Use softlimit to determine disk space, except when it has been exceeded */
1661 *bsize = D.bsize;
1662 if (r == -1) {
1663 if (errno == EDQUOT) {
1664 *dfree =0;
1665 *dsize =D.curblocks;
1666 return (True);
1667 } else {
1668 goto try_group_quota;
1672 /* Use softlimit to determine disk space, except when it has been exceeded */
1673 if (
1674 (D.softlimit && D.curblocks >= D.softlimit) ||
1675 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1676 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1677 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1679 *dfree = 0;
1680 *dsize = D.curblocks;
1681 } else if (D.softlimit==0 && D.hardlimit==0) {
1682 goto try_group_quota;
1683 } else {
1684 if (D.softlimit == 0)
1685 D.softlimit = D.hardlimit;
1686 *dfree = D.softlimit - D.curblocks;
1687 *dsize = D.softlimit;
1690 return True;
1692 try_group_quota:
1693 id.gid = getegid();
1695 ZERO_STRUCT(D);
1696 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1698 /* Use softlimit to determine disk space, except when it has been exceeded */
1699 *bsize = D.bsize;
1700 if (r == -1) {
1701 if (errno == EDQUOT) {
1702 *dfree =0;
1703 *dsize =D.curblocks;
1704 return (True);
1705 } else {
1706 return False;
1710 /* Use softlimit to determine disk space, except when it has been exceeded */
1711 if (
1712 (D.softlimit && D.curblocks >= D.softlimit) ||
1713 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1714 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1715 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1717 *dfree = 0;
1718 *dsize = D.curblocks;
1719 } else if (D.softlimit==0 && D.hardlimit==0) {
1720 return False;
1721 } else {
1722 if (D.softlimit == 0)
1723 D.softlimit = D.hardlimit;
1724 *dfree = D.softlimit - D.curblocks;
1725 *dsize = D.softlimit;
1728 return (True);
1730 #endif /* HAVE_SYS_QUOTAS */