s3: "dotareof" only looks at the file type
[Samba.git] / source3 / smbd / quotas.c
bloba424602d5fe519d44e5e5c908d1a2ab0af4f5f90
1 /*
2 Unix SMB/CIFS implementation.
3 support for quotas
4 Copyright (C) Andrew Tridgell 1992-1998
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
21 /*
22 * This is one of the most system dependent parts of Samba, and its
23 * done a litle differently. Each system has its own way of doing
24 * things :-(
27 #include "includes.h"
29 #undef DBGC_CLASS
30 #define DBGC_CLASS DBGC_QUOTA
32 #ifndef HAVE_SYS_QUOTAS
34 /* just a quick hack because sysquotas.h is included before linux/quota.h */
35 #ifdef QUOTABLOCK_SIZE
36 #undef QUOTABLOCK_SIZE
37 #endif
39 #ifdef WITH_QUOTAS
41 #if defined(VXFS_QUOTA)
44 * In addition to their native filesystems, some systems have Veritas VxFS.
45 * Declare here, define at end: reduces likely "include" interaction problems.
46 * David Lee <T.D.Lee@durham.ac.uk>
48 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
50 #endif /* VXFS_QUOTA */
52 #ifdef LINUX
54 #include <sys/types.h>
55 #include <mntent.h>
58 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
59 * So we include all the files has *should* be in the system into a large,
60 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
63 #include "samba_linux_quota.h"
65 typedef struct _LINUX_SMB_DISK_QUOTA {
66 uint64_t bsize;
67 uint64_t hardlimit; /* In bsize units. */
68 uint64_t softlimit; /* In bsize units. */
69 uint64_t curblocks; /* In bsize units. */
70 uint64_t ihardlimit; /* inode hard limit. */
71 uint64_t isoftlimit; /* inode soft limit. */
72 uint64_t curinodes; /* Current used inodes. */
73 } LINUX_SMB_DISK_QUOTA;
76 #ifdef HAVE_LINUX_DQBLK_XFS_H
77 #include <linux/dqblk_xfs.h>
79 /****************************************************************************
80 Abstract out the XFS Quota Manager quota get call.
81 ****************************************************************************/
83 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
85 struct fs_disk_quota D;
86 int ret;
88 ZERO_STRUCT(D);
90 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
92 if (ret)
93 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
95 if (ret)
96 return ret;
98 dp->bsize = (uint64_t)512;
99 dp->softlimit = (uint64_t)D.d_blk_softlimit;
100 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
101 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
102 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
103 dp->curinodes = (uint64_t)D.d_icount;
104 dp->curblocks = (uint64_t)D.d_bcount;
106 return ret;
108 #else
109 static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
111 DEBUG(0,("XFS quota support not available\n"));
112 errno = ENOSYS;
113 return -1;
115 #endif
118 /****************************************************************************
119 Abstract out the old and new Linux quota get calls.
120 ****************************************************************************/
122 static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
124 struct v1_kern_dqblk D;
125 int ret;
127 ZERO_STRUCT(D);
129 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
131 if (ret && errno != EDQUOT)
132 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
134 if (ret && errno != EDQUOT)
135 return ret;
137 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
138 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
139 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
140 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
141 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
142 dp->curinodes = (uint64_t)D.dqb_curinodes;
143 dp->curblocks = (uint64_t)D.dqb_curblocks;
145 return ret;
148 static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
150 struct v2_kern_dqblk D;
151 int ret;
153 ZERO_STRUCT(D);
155 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
157 if (ret && errno != EDQUOT)
158 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
160 if (ret && errno != EDQUOT)
161 return ret;
163 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
164 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
165 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
166 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
167 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
168 dp->curinodes = (uint64_t)D.dqb_curinodes;
169 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
171 return ret;
174 /****************************************************************************
175 Brand-new generic quota interface.
176 ****************************************************************************/
178 static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
180 struct if_dqblk D;
181 int ret;
183 ZERO_STRUCT(D);
185 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
187 if (ret && errno != EDQUOT)
188 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
190 if (ret && errno != EDQUOT)
191 return ret;
193 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
194 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
195 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
196 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
197 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
198 dp->curinodes = (uint64_t)D.dqb_curinodes;
199 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
201 return ret;
204 /****************************************************************************
205 Try to get the disk space from disk quotas (LINUX version).
206 ****************************************************************************/
208 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
210 int r;
211 SMB_STRUCT_STAT S;
212 FILE *fp;
213 LINUX_SMB_DISK_QUOTA D;
214 struct mntent *mnt;
215 SMB_DEV_T devno;
216 int found;
217 uid_t euser_id;
218 gid_t egrp_id;
220 ZERO_STRUCT(D);
222 euser_id = geteuid();
223 egrp_id = getegid();
225 /* find the block device file */
227 if ( sys_stat(path, &S, lp_fake_dir_create_times()) == -1 )
228 return(False) ;
230 devno = S.st_ex_dev ;
232 if ((fp = setmntent(MOUNTED,"r")) == NULL)
233 return(False) ;
235 found = False ;
237 while ((mnt = getmntent(fp))) {
238 if ( sys_stat(mnt->mnt_dir, &S, lp_fake_dir_create_times())
239 == -1 )
240 continue ;
242 if (S.st_ex_dev == devno) {
243 found = True ;
244 break;
248 endmntent(fp) ;
250 if (!found)
251 return(False);
253 become_root();
255 if (strcmp(mnt->mnt_type, "xfs")==0) {
256 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
257 } else {
258 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
259 if (r == -1 && errno != EDQUOT) {
260 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
261 if (r == -1 && errno != EDQUOT)
262 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
266 unbecome_root();
268 /* Use softlimit to determine disk space, except when it has been exceeded */
269 *bsize = D.bsize;
270 if (r == -1) {
271 if (errno == EDQUOT) {
272 *dfree =0;
273 *dsize =D.curblocks;
274 return (True);
275 } else {
276 return(False);
280 /* Use softlimit to determine disk space, except when it has been exceeded */
281 if (
282 (D.softlimit && D.curblocks >= D.softlimit) ||
283 (D.hardlimit && D.curblocks >= D.hardlimit) ||
284 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
285 (D.ihardlimit && D.curinodes>=D.ihardlimit)
287 *dfree = 0;
288 *dsize = D.curblocks;
289 } else if (D.softlimit==0 && D.hardlimit==0) {
290 return(False);
291 } else {
292 if (D.softlimit == 0)
293 D.softlimit = D.hardlimit;
294 *dfree = D.softlimit - D.curblocks;
295 *dsize = D.softlimit;
298 return (True);
301 #elif defined(CRAY)
303 #include <sys/quota.h>
304 #include <mntent.h>
306 /****************************************************************************
307 try to get the disk space from disk quotas (CRAY VERSION)
308 ****************************************************************************/
310 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
312 struct mntent *mnt;
313 FILE *fd;
314 SMB_STRUCT_STAT sbuf;
315 SMB_DEV_T devno ;
316 struct q_request request ;
317 struct qf_header header ;
318 int quota_default = 0 ;
319 bool found = false;
321 if (sys_stat(path, &sbuf, lp_fake_dir_create_times()) == -1) {
322 return false;
325 devno = sbuf.st_ex_dev ;
327 if ((fd = setmntent(KMTAB)) == NULL) {
328 return false;
331 while ((mnt = getmntent(fd)) != NULL) {
332 if (sys_stat(mnt->mnt_dir, &sbuf, lp_fake_dir_create_times())
333 == -1) {
334 continue;
336 if (sbuf.st_ex_dev == devno) {
337 found = frue ;
338 break;
342 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
343 endmntent(fd);
344 if (!found) {
345 return false;
348 if (!name) {
349 return false;
352 request.qf_magic = QF_MAGIC ;
353 request.qf_entry.id = geteuid() ;
355 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
356 return false;
359 if (!request.user) {
360 return False;
363 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
364 if (!quota_default) {
365 if (quotactl(name, Q_GETHEADER, &header) == -1) {
366 return false;
367 } else {
368 quota_default = header.user_h.def_fq;
371 *dfree = quota_default;
372 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
373 *dfree = 0;
374 } else {
375 *dfree = request.qf_entry.user_q.f_quota;
378 *dsize = request.qf_entry.user_q.f_use;
380 if (*dfree < *dsize) {
381 *dfree = 0;
382 } else {
383 *dfree -= *dsize;
386 *bsize = 4096 ; /* Cray blocksize */
387 return true;
391 #elif defined(SUNOS5) || defined(SUNOS4)
393 #include <fcntl.h>
394 #include <sys/param.h>
395 #if defined(SUNOS5)
396 #include <sys/fs/ufs_quota.h>
397 #include <sys/mnttab.h>
398 #include <sys/mntent.h>
399 #else /* defined(SUNOS4) */
400 #include <ufs/quota.h>
401 #include <mntent.h>
402 #endif
404 #if defined(SUNOS5)
406 /****************************************************************************
407 Allows querying of remote hosts for quotas on NFS mounted shares.
408 Supports normal NFS and AMD mounts.
409 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
410 ****************************************************************************/
412 #include <rpc/rpc.h>
413 #include <rpc/types.h>
414 #include <rpcsvc/rquota.h>
415 #include <rpc/nettype.h>
416 #include <rpc/xdr.h>
418 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
420 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
421 return(0);
422 if (!xdr_int(xdrsp, &args->gqa_uid))
423 return(0);
424 return (1);
427 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
429 int quotastat;
431 if (!xdr_int(xdrsp, &quotastat)) {
432 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
433 return 0;
435 gqr->status = quotastat;
437 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
438 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
439 return 0;
441 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
442 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
443 return 0;
445 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
446 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
447 return 0;
449 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
450 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
451 return 0;
453 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
454 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
455 return 0;
457 return (1);
460 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
461 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
463 uid_t uid = euser_id;
464 struct dqblk D;
465 char *mnttype = nfspath;
466 CLIENT *clnt;
467 struct getquota_rslt gqr;
468 struct getquota_args args;
469 char *cutstr, *pathname, *host, *testpath;
470 int len;
471 static struct timeval timeout = {2,0};
472 enum clnt_stat clnt_stat;
473 bool ret = True;
475 *bsize = *dfree = *dsize = (uint64_t)0;
477 len=strcspn(mnttype, ":");
478 pathname=strstr(mnttype, ":");
479 cutstr = (char *) SMB_MALLOC(len+1);
480 if (!cutstr)
481 return False;
483 memset(cutstr, '\0', len+1);
484 host = strncat(cutstr,mnttype, sizeof(char) * len );
485 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
486 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
487 testpath=strchr_m(mnttype, ':');
488 args.gqa_pathp = testpath+1;
489 args.gqa_uid = uid;
491 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
493 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
494 ret = False;
495 goto out;
498 clnt->cl_auth = authunix_create_default();
499 DEBUG(9,("nfs_quotas: auth_success\n"));
501 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
503 if (clnt_stat != RPC_SUCCESS) {
504 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
505 ret = False;
506 goto out;
510 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
511 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
512 * something sensible.
515 switch (gqr.status) {
516 case 0:
517 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
518 ret = False;
519 goto out;
521 case 1:
522 DEBUG(9,("nfs_quotas: Good quota data\n"));
523 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
524 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
525 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
526 break;
528 case 2:
529 case 3:
530 D.dqb_bsoftlimit = 1;
531 D.dqb_curblocks = 1;
532 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
533 break;
535 default:
536 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
537 break;
540 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",
541 gqr.status,
542 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
543 gqr.getquota_rslt_u.gqr_rquota.rq_active,
544 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
545 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
546 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
548 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
549 *dsize = D.dqb_bsoftlimit;
551 if (D.dqb_curblocks == 1)
552 *bsize = 512;
554 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
555 *dfree = 0;
556 *dsize = D.dqb_curblocks;
557 } else
558 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
560 out:
562 if (clnt) {
563 if (clnt->cl_auth)
564 auth_destroy(clnt->cl_auth);
565 clnt_destroy(clnt);
568 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
570 SAFE_FREE(cutstr);
571 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
572 return ret;
574 #endif
576 /****************************************************************************
577 try to get the disk space from disk quotas (SunOS & Solaris2 version)
578 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
579 ****************************************************************************/
581 bool disk_quotas(const char *path,
582 uint64_t *bsize,
583 uint64_t *dfree,
584 uint64_t *dsize)
586 uid_t euser_id;
587 int ret;
588 struct dqblk D;
589 #if defined(SUNOS5)
590 struct quotctl command;
591 int file;
592 struct mnttab mnt;
593 #else /* SunOS4 */
594 struct mntent *mnt;
595 #endif
596 char *name = NULL;
597 FILE *fd;
598 SMB_STRUCT_STAT sbuf;
599 SMB_DEV_T devno;
600 bool found = false;
602 euser_id = geteuid();
604 if (sys_stat(path, &sbuf, lp_fake_dir_create_times()) == -1) {
605 return false;
608 devno = sbuf.st_ex_dev ;
609 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
610 path, (unsigned int)devno));
611 #if defined(SUNOS5)
612 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
613 return false;
616 while (getmntent(fd, &mnt) == 0) {
617 if (sys_stat(mnt.mnt_mountp, &sbuf,
618 lp_fake_dir_create_times()) == -1) {
619 continue;
622 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
623 mnt.mnt_mountp, (unsigned int)devno));
625 /* quotas are only on vxfs, UFS or NFS */
626 if ((sbuf.st_ex_dev == devno) && (
627 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
628 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
629 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
630 found = true;
631 name = talloc_asprintf(talloc_tos(),
632 "%s/quotas",
633 mnt.mnt_mountp);
634 break;
638 fclose(fd);
639 #else /* SunOS4 */
640 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
641 return false;
644 while ((mnt = getmntent(fd)) != NULL) {
645 if (sys_stat(mnt->mnt_dir, &sbuf,
646 lp_fake_dir_create_times()) == -1) {
647 continue;
649 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
650 mnt->mnt_dir,
651 (unsigned int)sbuf.st_ex_dev));
652 if (sbuf.st_ex_dev == devno) {
653 found = true;
654 name = talloc_strdup(talloc_tos(),
655 mnt->mnt_fsname);
656 break;
660 endmntent(fd);
661 #endif
662 if (!found) {
663 return false;
666 if (!name) {
667 return false;
669 become_root();
671 #if defined(SUNOS5)
672 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
673 bool retval;
674 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
675 mnt.mnt_special));
676 retval = nfs_quotas(mnt.mnt_special,
677 euser_id, bsize, dfree, dsize);
678 unbecome_root();
679 return retval;
682 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
683 if((file=sys_open(name, O_RDONLY,0))<0) {
684 unbecome_root();
685 return false;
687 command.op = Q_GETQUOTA;
688 command.uid = euser_id;
689 command.addr = (caddr_t) &D;
690 ret = ioctl(file, Q_QUOTACTL, &command);
691 close(file);
692 #else
693 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
694 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
695 #endif
697 unbecome_root();
699 if (ret < 0) {
700 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
701 strerror(errno) ));
703 #if defined(SUNOS5) && defined(VXFS_QUOTA)
704 /* If normal quotactl() fails, try vxfs private calls */
705 set_effective_uid(euser_id);
706 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
707 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
708 bool retval;
709 retval = disk_quotas_vxfs(name, path,
710 bsize, dfree, dsize);
711 return retval;
713 #else
714 return false;
715 #endif
718 /* If softlimit is zero, set it equal to hardlimit.
721 if (D.dqb_bsoftlimit==0) {
722 D.dqb_bsoftlimit = D.dqb_bhardlimit;
725 /* Use softlimit to determine disk space. A user exceeding the quota
726 * is told that there's no space left. Writes might actually work for
727 * a bit if the hardlimit is set higher than softlimit. Effectively
728 * the disk becomes made of rubber latex and begins to expand to
729 * accommodate the user :-)
732 if (D.dqb_bsoftlimit==0)
733 return(False);
734 *bsize = DEV_BSIZE;
735 *dsize = D.dqb_bsoftlimit;
737 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
738 *dfree = 0;
739 *dsize = D.dqb_curblocks;
740 } else {
741 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
744 DEBUG(5,("disk_quotas for path \"%s\" returning "
745 "bsize %.0f, dfree %.0f, dsize %.0f\n",
746 path,(double)*bsize,(double)*dfree,(double)*dsize));
748 return true;
752 #elif defined(OSF1)
753 #include <ufs/quota.h>
755 /****************************************************************************
756 try to get the disk space from disk quotas - OSF1 version
757 ****************************************************************************/
759 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
761 int r, save_errno;
762 struct dqblk D;
763 SMB_STRUCT_STAT S;
764 uid_t euser_id;
767 * This code presumes that OSF1 will only
768 * give out quota info when the real uid
769 * matches the effective uid. JRA.
771 euser_id = geteuid();
772 save_re_uid();
773 if (set_re_uid() != 0) return False;
775 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
776 if (r) {
777 save_errno = errno;
780 restore_re_uid();
782 *bsize = DEV_BSIZE;
784 if (r)
786 if (save_errno == EDQUOT) /* disk quota exceeded */
788 *dfree = 0;
789 *dsize = D.dqb_curblocks;
790 return (True);
792 else
793 return (False);
796 /* If softlimit is zero, set it equal to hardlimit.
799 if (D.dqb_bsoftlimit==0)
800 D.dqb_bsoftlimit = D.dqb_bhardlimit;
802 /* Use softlimit to determine disk space, except when it has been exceeded */
804 if (D.dqb_bsoftlimit==0)
805 return(False);
807 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
808 *dfree = 0;
809 *dsize = D.dqb_curblocks;
810 } else {
811 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
812 *dsize = D.dqb_bsoftlimit;
814 return (True);
817 #elif defined (IRIX6)
818 /****************************************************************************
819 try to get the disk space from disk quotas (IRIX 6.2 version)
820 ****************************************************************************/
822 #include <sys/quota.h>
823 #include <mntent.h>
825 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
827 uid_t euser_id;
828 int r;
829 struct dqblk D;
830 struct fs_disk_quota F;
831 SMB_STRUCT_STAT S;
832 FILE *fp;
833 struct mntent *mnt;
834 SMB_DEV_T devno;
835 int found;
837 /* find the block device file */
839 if ( sys_stat(path, &S, lp_fake_dir_create_times()) == -1 ) {
840 return(False) ;
843 devno = S.st_ex_dev ;
845 fp = setmntent(MOUNTED,"r");
846 found = False ;
848 while ((mnt = getmntent(fp))) {
849 if ( sys_stat(mnt->mnt_dir, &S, lp_fake_dir_create_times()) == -1 )
850 continue ;
851 if (S.st_ex_dev == devno) {
852 found = True ;
853 break ;
856 endmntent(fp) ;
858 if (!found) {
859 return(False);
862 euser_id=geteuid();
863 become_root();
865 /* Use softlimit to determine disk space, except when it has been exceeded */
867 *bsize = 512;
869 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
871 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
873 unbecome_root();
875 if (r==-1)
876 return(False);
878 /* Use softlimit to determine disk space, except when it has been exceeded */
879 if (
880 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
881 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
882 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
883 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
886 *dfree = 0;
887 *dsize = D.dqb_curblocks;
889 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
891 return(False);
893 else
895 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
896 *dsize = D.dqb_bsoftlimit;
900 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
902 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
904 unbecome_root();
906 if (r==-1)
908 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
909 return(False);
912 /* No quota for this user. */
913 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
915 return(False);
918 /* Use softlimit to determine disk space, except when it has been exceeded */
919 if (
920 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
921 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
922 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
923 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
926 *dfree = 0;
927 *dsize = F.d_bcount;
929 else
931 *dfree = (F.d_blk_softlimit - F.d_bcount);
932 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
936 else
938 unbecome_root();
939 return(False);
942 return (True);
946 #else
948 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
949 #include <ufs/ufs/quota.h>
950 #include <machine/param.h>
951 #elif AIX
952 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
953 #include <jfs/quota.h>
954 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
955 #define dqb_curfiles dqb_curinodes
956 #define dqb_fhardlimit dqb_ihardlimit
957 #define dqb_fsoftlimit dqb_isoftlimit
958 #ifdef _AIXVERSION_530
959 #include <sys/statfs.h>
960 #include <sys/vmount.h>
961 #endif /* AIX 5.3 */
962 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
963 #include <sys/quota.h>
964 #include <devnm.h>
965 #endif
967 #if defined(__FreeBSD__) || defined(__DragonFly__)
969 #include <rpc/rpc.h>
970 #include <rpc/types.h>
971 #include <rpcsvc/rquota.h>
972 #ifdef HAVE_RPC_NETTYPE_H
973 #include <rpc/nettype.h>
974 #endif
975 #include <rpc/xdr.h>
977 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
979 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
980 return(0);
981 if (!xdr_int(xdrsp, &args->gqa_uid))
982 return(0);
983 return (1);
986 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
988 int quotastat;
990 if (!xdr_int(xdrsp, &quotastat)) {
991 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
992 return 0;
994 gqr->status = quotastat;
996 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
997 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
998 return 0;
1000 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1001 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1002 return 0;
1004 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1005 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1006 return 0;
1008 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1009 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1010 return 0;
1012 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1013 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1014 return 0;
1016 return (1);
1019 /* Works on FreeBSD, too. :-) */
1020 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1022 uid_t uid = euser_id;
1023 struct dqblk D;
1024 char *mnttype = nfspath;
1025 CLIENT *clnt;
1026 struct getquota_rslt gqr;
1027 struct getquota_args args;
1028 char *cutstr, *pathname, *host, *testpath;
1029 int len;
1030 static struct timeval timeout = {2,0};
1031 enum clnt_stat clnt_stat;
1032 bool ret = True;
1034 *bsize = *dfree = *dsize = (uint64_t)0;
1036 len=strcspn(mnttype, ":");
1037 pathname=strstr(mnttype, ":");
1038 cutstr = (char *) SMB_MALLOC(len+1);
1039 if (!cutstr)
1040 return False;
1042 memset(cutstr, '\0', len+1);
1043 host = strncat(cutstr,mnttype, sizeof(char) * len );
1044 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1045 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1046 testpath=strchr_m(mnttype, ':');
1047 args.gqa_pathp = testpath+1;
1048 args.gqa_uid = uid;
1050 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1052 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1053 ret = False;
1054 goto out;
1057 clnt->cl_auth = authunix_create_default();
1058 DEBUG(9,("nfs_quotas: auth_success\n"));
1060 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);
1062 if (clnt_stat != RPC_SUCCESS) {
1063 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1064 ret = False;
1065 goto out;
1069 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1070 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1071 * something sensible.
1074 switch (gqr.status) {
1075 case 0:
1076 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1077 ret = False;
1078 goto out;
1080 case 1:
1081 DEBUG(9,("nfs_quotas: Good quota data\n"));
1082 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1083 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1084 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1085 break;
1087 case 2:
1088 case 3:
1089 D.dqb_bsoftlimit = 1;
1090 D.dqb_curblocks = 1;
1091 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1092 break;
1094 default:
1095 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1096 break;
1099 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",
1100 gqr.status,
1101 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1102 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1103 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1104 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1105 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1107 if (D.dqb_bsoftlimit == 0)
1108 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1109 if (D.dqb_bsoftlimit == 0)
1110 return False;
1112 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1113 *dsize = D.dqb_bsoftlimit;
1115 if (D.dqb_curblocks == 1)
1116 *bsize = DEV_BSIZE;
1118 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1119 *dfree = 0;
1120 *dsize = D.dqb_curblocks;
1121 } else
1122 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1124 out:
1126 if (clnt) {
1127 if (clnt->cl_auth)
1128 auth_destroy(clnt->cl_auth);
1129 clnt_destroy(clnt);
1132 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1134 SAFE_FREE(cutstr);
1135 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1136 return ret;
1139 #endif
1141 /****************************************************************************
1142 try to get the disk space from disk quotas - default version
1143 ****************************************************************************/
1145 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1147 int r;
1148 struct dqblk D;
1149 uid_t euser_id;
1150 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1151 char dev_disk[256];
1152 SMB_STRUCT_STAT S;
1154 /* find the block device file */
1156 #ifdef HPUX
1157 /* Need to set the cache flag to 1 for HPUX. Seems
1158 * to have a significant performance boost when
1159 * lstat calls on /dev access this function.
1161 if ((sys_stat(path, &S, lp_fake_dir_create_times())<0)
1162 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1163 #else
1164 if ((sys_stat(path, &S, lp_fake_dir_create_times())<0)
1165 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1166 return (False);
1167 #endif /* ifdef HPUX */
1169 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1171 euser_id = geteuid();
1173 #ifdef HPUX
1174 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1175 save_re_uid();
1176 if (set_re_uid() != 0) return False;
1178 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1180 restore_re_uid();
1181 #else
1182 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1184 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1185 gid_t egrp_id;
1186 #if defined(__FreeBSD__) || defined(__DragonFly__)
1187 SMB_DEV_T devno;
1188 struct statfs *mnts;
1189 SMB_STRUCT_STAT st;
1190 int mntsize, i;
1192 if (sys_stat(path, &st, lp_fake_dir_create_times()) < 0)
1193 return False;
1194 devno = st.st_ex_dev;
1196 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1197 if (mntsize <= 0)
1198 return False;
1200 for (i = 0; i < mntsize; i++) {
1201 if (sys_stat(mnts[i].f_mntonname, &st, lp_fake_dir_create_times()) < 0)
1202 return False;
1203 if (st.st_ex_dev == devno)
1204 break;
1206 if (i == mntsize)
1207 return False;
1208 #endif
1210 become_root();
1212 #if defined(__FreeBSD__) || defined(__DragonFly__)
1213 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1214 bool retval;
1215 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1216 unbecome_root();
1217 return retval;
1219 #endif
1221 egrp_id = getegid();
1222 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1224 /* As FreeBSD has group quotas, if getting the user
1225 quota fails, try getting the group instead. */
1226 if (r) {
1227 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1230 unbecome_root();
1232 #elif defined(AIX)
1233 /* AIX has both USER and GROUP quotas:
1234 Get the USER quota (ohnielse@fysik.dtu.dk) */
1235 #ifdef _AIXVERSION_530
1237 struct statfs statbuf;
1238 quota64_t user_quota;
1239 if (statfs(path,&statbuf) != 0)
1240 return False;
1241 if(statbuf.f_vfstype == MNT_J2)
1243 /* For some reason we need to be root for jfs2 */
1244 become_root();
1245 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1246 unbecome_root();
1247 /* Copy results to old struct to let the following code work as before */
1248 D.dqb_curblocks = user_quota.bused;
1249 D.dqb_bsoftlimit = user_quota.bsoft;
1250 D.dqb_bhardlimit = user_quota.bhard;
1251 D.dqb_curfiles = user_quota.iused;
1252 D.dqb_fsoftlimit = user_quota.isoft;
1253 D.dqb_fhardlimit = user_quota.ihard;
1255 else if(statbuf.f_vfstype == MNT_JFS)
1257 #endif /* AIX 5.3 */
1258 save_re_uid();
1259 if (set_re_uid() != 0)
1260 return False;
1261 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1262 restore_re_uid();
1263 #ifdef _AIXVERSION_530
1265 else
1266 r = 1; /* Fail for other FS-types */
1268 #endif /* AIX 5.3 */
1269 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1270 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1271 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1272 #endif /* HPUX */
1274 /* Use softlimit to determine disk space, except when it has been exceeded */
1275 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1276 *bsize = DEV_BSIZE;
1277 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1278 *bsize = 1024;
1279 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1281 if (r)
1283 if (errno == EDQUOT)
1285 *dfree =0;
1286 *dsize =D.dqb_curblocks;
1287 return (True);
1289 else return(False);
1292 /* If softlimit is zero, set it equal to hardlimit.
1295 if (D.dqb_bsoftlimit==0)
1296 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1298 if (D.dqb_bsoftlimit==0)
1299 return(False);
1300 /* Use softlimit to determine disk space, except when it has been exceeded */
1301 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1302 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1303 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1304 #endif
1306 *dfree = 0;
1307 *dsize = D.dqb_curblocks;
1309 else {
1310 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1311 *dsize = D.dqb_bsoftlimit;
1313 return (True);
1316 #endif
1318 #if defined(VXFS_QUOTA)
1320 /****************************************************************************
1321 Try to get the disk space from Veritas disk quotas.
1322 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1324 Background assumptions:
1325 Potentially under many Operating Systems. Initially Solaris 2.
1327 My guess is that Veritas is largely, though not entirely,
1328 independent of OS. So I have separated it out.
1330 There may be some details. For example, OS-specific "include" files.
1332 It is understood that HPUX 10 somehow gets Veritas quotas without
1333 any special effort; if so, this routine need not be compiled in.
1334 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1336 Warning:
1337 It is understood that Veritas do not publicly support this ioctl interface.
1338 Rather their preference would be for the user (us) to call the native
1339 OS and then for the OS itself to call through to the VxFS filesystem.
1340 Presumably HPUX 10, see above, does this.
1342 Hints for porting:
1343 Add your OS to "IFLIST" below.
1344 Get it to compile successfully:
1345 Almost certainly "include"s require attention: see SUNOS5.
1346 In the main code above, arrange for it to be called: see SUNOS5.
1347 Test!
1349 ****************************************************************************/
1351 /* "IFLIST"
1352 * This "if" is a list of ports:
1353 * if defined(OS1) || defined(OS2) || ...
1355 #if defined(SUNOS5)
1357 #if defined(SUNOS5)
1358 #include <sys/fs/vx_solaris.h>
1359 #endif
1360 #include <sys/fs/vx_machdep.h>
1361 #include <sys/fs/vx_layout.h>
1362 #include <sys/fs/vx_quota.h>
1363 #include <sys/fs/vx_aioctl.h>
1364 #include <sys/fs/vx_ioctl.h>
1366 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1368 uid_t user_id, euser_id;
1369 int ret;
1370 struct vx_dqblk D;
1371 struct vx_quotctl quotabuf;
1372 struct vx_genioctl genbuf;
1373 char *qfname;
1374 int file;
1377 * "name" may or may not include a trailing "/quotas".
1378 * Arranging consistency of calling here in "quotas.c" may not be easy and
1379 * it might be easier to examine and adjust it here.
1380 * Fortunately, VxFS seems not to mind at present.
1382 qfname = talloc_strdup(talloc_tos(), name);
1383 if (!qfname) {
1384 return false;
1386 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1388 euser_id = geteuid();
1389 set_effective_uid(0);
1391 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1392 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1393 set_effective_uid(euser_id);
1394 return(False);
1396 genbuf.ioc_cmd = VX_QUOTACTL;
1397 genbuf.ioc_up = (void *) &quotabuf;
1399 quotabuf.cmd = VX_GETQUOTA;
1400 quotabuf.uid = euser_id;
1401 quotabuf.addr = (caddr_t) &D;
1402 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1403 close(file);
1405 set_effective_uid(euser_id);
1407 if (ret < 0) {
1408 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1409 return(False);
1412 /* If softlimit is zero, set it equal to hardlimit.
1415 if (D.dqb_bsoftlimit==0)
1416 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1418 /* Use softlimit to determine disk space. A user exceeding the quota is told
1419 * that there's no space left. Writes might actually work for a bit if the
1420 * hardlimit is set higher than softlimit. Effectively the disk becomes
1421 * made of rubber latex and begins to expand to accommodate the user :-)
1423 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1424 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1425 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1427 if (D.dqb_bsoftlimit==0)
1428 return(False);
1429 *bsize = DEV_BSIZE;
1430 *dsize = D.dqb_bsoftlimit;
1432 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1433 *dfree = 0;
1434 *dsize = D.dqb_curblocks;
1435 } else
1436 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1438 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1439 path,(double)*bsize,(double)*dfree,(double)*dsize));
1441 return(True);
1444 #endif /* SUNOS5 || ... */
1446 #endif /* VXFS_QUOTA */
1448 #else /* WITH_QUOTAS */
1450 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1452 (*bsize) = 512; /* This value should be ignored */
1454 /* And just to be sure we set some values that hopefully */
1455 /* will be larger that any possible real-world value */
1456 (*dfree) = (uint64_t)-1;
1457 (*dsize) = (uint64_t)-1;
1459 /* As we have select not to use quotas, allways fail */
1460 return false;
1462 #endif /* WITH_QUOTAS */
1464 #else /* HAVE_SYS_QUOTAS */
1465 /* wrapper to the new sys_quota interface
1466 this file should be removed later
1468 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1470 int r;
1471 SMB_DISK_QUOTA D;
1472 unid_t id;
1474 id.uid = geteuid();
1476 ZERO_STRUCT(D);
1477 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1479 /* Use softlimit to determine disk space, except when it has been exceeded */
1480 *bsize = D.bsize;
1481 if (r == -1) {
1482 if (errno == EDQUOT) {
1483 *dfree =0;
1484 *dsize =D.curblocks;
1485 return (True);
1486 } else {
1487 goto try_group_quota;
1491 /* Use softlimit to determine disk space, except when it has been exceeded */
1492 if (
1493 (D.softlimit && D.curblocks >= D.softlimit) ||
1494 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1495 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1496 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1498 *dfree = 0;
1499 *dsize = D.curblocks;
1500 } else if (D.softlimit==0 && D.hardlimit==0) {
1501 goto try_group_quota;
1502 } else {
1503 if (D.softlimit == 0)
1504 D.softlimit = D.hardlimit;
1505 *dfree = D.softlimit - D.curblocks;
1506 *dsize = D.softlimit;
1509 return True;
1511 try_group_quota:
1512 id.gid = getegid();
1514 ZERO_STRUCT(D);
1515 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1517 /* Use softlimit to determine disk space, except when it has been exceeded */
1518 *bsize = D.bsize;
1519 if (r == -1) {
1520 if (errno == EDQUOT) {
1521 *dfree =0;
1522 *dsize =D.curblocks;
1523 return (True);
1524 } else {
1525 return False;
1529 /* Use softlimit to determine disk space, except when it has been exceeded */
1530 if (
1531 (D.softlimit && D.curblocks >= D.softlimit) ||
1532 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1533 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1534 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1536 *dfree = 0;
1537 *dsize = D.curblocks;
1538 } else if (D.softlimit==0 && D.hardlimit==0) {
1539 return False;
1540 } else {
1541 if (D.softlimit == 0)
1542 D.softlimit = D.hardlimit;
1543 *dfree = D.softlimit - D.curblocks;
1544 *dsize = D.softlimit;
1547 return (True);
1549 #endif /* HAVE_SYS_QUOTAS */