s3-smbd: Remove Linux support from old (pre-sysquotas) code
[Samba/gebeck_regimport.git] / source3 / smbd / quotas.c
blob0179e928d7b935396e1e5250a6be95be6f59b3c8
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 #if defined(SUNOS5) || defined(SUNOS4)
57 #include <fcntl.h>
58 #include <sys/param.h>
59 #if defined(SUNOS5)
60 #include <sys/fs/ufs_quota.h>
61 #include <sys/mnttab.h>
62 #include <sys/mntent.h>
63 #else /* defined(SUNOS4) */
64 #include <ufs/quota.h>
65 #include <mntent.h>
66 #endif
68 #if defined(SUNOS5)
70 /****************************************************************************
71 Allows querying of remote hosts for quotas on NFS mounted shares.
72 Supports normal NFS and AMD mounts.
73 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
74 ****************************************************************************/
76 #include <rpc/rpc.h>
77 #include <rpc/types.h>
78 #include <rpcsvc/rquota.h>
79 #include <rpc/nettype.h>
80 #include <rpc/xdr.h>
82 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
84 int quotastat;
86 if (!xdr_int(xdrsp, &quotastat)) {
87 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
88 return 0;
90 gqr->status = quotastat;
92 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
93 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
94 return 0;
96 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
97 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
98 return 0;
100 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
101 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
102 return 0;
104 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
105 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
106 return 0;
108 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
109 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
110 return 0;
112 return (1);
115 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
116 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
118 uid_t uid = euser_id;
119 struct dqblk D;
120 char *mnttype = nfspath;
121 CLIENT *clnt;
122 struct getquota_rslt gqr;
123 struct getquota_args args;
124 char *cutstr, *pathname, *host, *testpath;
125 int len;
126 static struct timeval timeout = {2,0};
127 enum clnt_stat clnt_stat;
128 bool ret = True;
130 *bsize = *dfree = *dsize = (uint64_t)0;
132 len=strcspn(mnttype, ":");
133 pathname=strstr(mnttype, ":");
134 cutstr = (char *) SMB_MALLOC(len+1);
135 if (!cutstr)
136 return False;
138 memset(cutstr, '\0', len+1);
139 host = strncat(cutstr,mnttype, sizeof(char) * len );
140 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
141 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
142 testpath=strchr_m(mnttype, ':');
143 args.gqa_pathp = testpath+1;
144 args.gqa_uid = uid;
146 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
148 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
149 ret = False;
150 goto out;
153 clnt->cl_auth = authunix_create_default();
154 DEBUG(9,("nfs_quotas: auth_success\n"));
156 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
158 if (clnt_stat != RPC_SUCCESS) {
159 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
160 ret = False;
161 goto out;
165 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
166 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
167 * something sensible.
170 switch (gqr.status) {
171 case 0:
172 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
173 ret = False;
174 goto out;
176 case 1:
177 DEBUG(9,("nfs_quotas: Good quota data\n"));
178 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
179 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
180 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
181 break;
183 case 2:
184 case 3:
185 D.dqb_bsoftlimit = 1;
186 D.dqb_curblocks = 1;
187 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
188 break;
190 default:
191 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
192 break;
195 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",
196 gqr.status,
197 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
198 gqr.getquota_rslt_u.gqr_rquota.rq_active,
199 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
200 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
201 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
203 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
204 *dsize = D.dqb_bsoftlimit;
206 if (D.dqb_curblocks == 1)
207 *bsize = 512;
209 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
210 *dfree = 0;
211 *dsize = D.dqb_curblocks;
212 } else
213 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
215 out:
217 if (clnt) {
218 if (clnt->cl_auth)
219 auth_destroy(clnt->cl_auth);
220 clnt_destroy(clnt);
223 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
225 SAFE_FREE(cutstr);
226 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
227 return ret;
229 #endif
231 /****************************************************************************
232 try to get the disk space from disk quotas (SunOS & Solaris2 version)
233 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
234 ****************************************************************************/
236 bool disk_quotas(const char *path,
237 uint64_t *bsize,
238 uint64_t *dfree,
239 uint64_t *dsize)
241 uid_t euser_id;
242 int ret;
243 struct dqblk D;
244 #if defined(SUNOS5)
245 struct quotctl command;
246 int file;
247 struct mnttab mnt;
248 #else /* SunOS4 */
249 struct mntent *mnt;
250 #endif
251 char *name = NULL;
252 FILE *fd;
253 SMB_STRUCT_STAT sbuf;
254 SMB_DEV_T devno;
255 bool found = false;
257 euser_id = geteuid();
259 if (sys_stat(path, &sbuf, false) == -1) {
260 return false;
263 devno = sbuf.st_ex_dev ;
264 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
265 path, (unsigned int)devno));
266 #if defined(SUNOS5)
267 if ((fd = fopen(MNTTAB, "r")) == NULL) {
268 return false;
271 while (getmntent(fd, &mnt) == 0) {
272 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
273 continue;
276 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
277 mnt.mnt_mountp, (unsigned int)devno));
279 /* quotas are only on vxfs, UFS or NFS */
280 if ((sbuf.st_ex_dev == devno) && (
281 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
282 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
283 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
284 found = true;
285 name = talloc_asprintf(talloc_tos(),
286 "%s/quotas",
287 mnt.mnt_mountp);
288 break;
292 fclose(fd);
293 #else /* SunOS4 */
294 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
295 return false;
298 while ((mnt = getmntent(fd)) != NULL) {
299 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
300 continue;
302 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
303 mnt->mnt_dir,
304 (unsigned int)sbuf.st_ex_dev));
305 if (sbuf.st_ex_dev == devno) {
306 found = true;
307 name = talloc_strdup(talloc_tos(),
308 mnt->mnt_fsname);
309 break;
313 endmntent(fd);
314 #endif
315 if (!found) {
316 return false;
319 if (!name) {
320 return false;
322 become_root();
324 #if defined(SUNOS5)
325 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
326 bool retval;
327 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
328 mnt.mnt_special));
329 retval = nfs_quotas(mnt.mnt_special,
330 euser_id, bsize, dfree, dsize);
331 unbecome_root();
332 return retval;
335 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
336 if((file=open(name, O_RDONLY,0))<0) {
337 unbecome_root();
338 return false;
340 command.op = Q_GETQUOTA;
341 command.uid = euser_id;
342 command.addr = (caddr_t) &D;
343 ret = ioctl(file, Q_QUOTACTL, &command);
344 close(file);
345 #else
346 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
347 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
348 #endif
350 unbecome_root();
352 if (ret < 0) {
353 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
354 strerror(errno) ));
356 #if defined(SUNOS5) && defined(VXFS_QUOTA)
357 /* If normal quotactl() fails, try vxfs private calls */
358 set_effective_uid(euser_id);
359 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
360 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
361 bool retval;
362 retval = disk_quotas_vxfs(name, path,
363 bsize, dfree, dsize);
364 return retval;
366 #else
367 return false;
368 #endif
371 /* If softlimit is zero, set it equal to hardlimit.
374 if (D.dqb_bsoftlimit==0) {
375 D.dqb_bsoftlimit = D.dqb_bhardlimit;
378 /* Use softlimit to determine disk space. A user exceeding the quota
379 * is told that there's no space left. Writes might actually work for
380 * a bit if the hardlimit is set higher than softlimit. Effectively
381 * the disk becomes made of rubber latex and begins to expand to
382 * accommodate the user :-)
385 if (D.dqb_bsoftlimit==0)
386 return(False);
387 *bsize = DEV_BSIZE;
388 *dsize = D.dqb_bsoftlimit;
390 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
391 *dfree = 0;
392 *dsize = D.dqb_curblocks;
393 } else {
394 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
397 DEBUG(5,("disk_quotas for path \"%s\" returning "
398 "bsize %.0f, dfree %.0f, dsize %.0f\n",
399 path,(double)*bsize,(double)*dfree,(double)*dsize));
401 return true;
405 #elif defined(OSF1)
406 #include <ufs/quota.h>
408 /****************************************************************************
409 try to get the disk space from disk quotas - OSF1 version
410 ****************************************************************************/
412 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
414 int r, save_errno;
415 struct dqblk D;
416 SMB_STRUCT_STAT S;
417 uid_t euser_id;
420 * This code presumes that OSF1 will only
421 * give out quota info when the real uid
422 * matches the effective uid. JRA.
424 euser_id = geteuid();
425 save_re_uid();
426 if (set_re_uid() != 0) return False;
428 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
429 if (r) {
430 save_errno = errno;
433 restore_re_uid();
435 *bsize = DEV_BSIZE;
437 if (r)
439 if (save_errno == EDQUOT) /* disk quota exceeded */
441 *dfree = 0;
442 *dsize = D.dqb_curblocks;
443 return (True);
445 else
446 return (False);
449 /* If softlimit is zero, set it equal to hardlimit.
452 if (D.dqb_bsoftlimit==0)
453 D.dqb_bsoftlimit = D.dqb_bhardlimit;
455 /* Use softlimit to determine disk space, except when it has been exceeded */
457 if (D.dqb_bsoftlimit==0)
458 return(False);
460 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
461 *dfree = 0;
462 *dsize = D.dqb_curblocks;
463 } else {
464 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
465 *dsize = D.dqb_bsoftlimit;
467 return (True);
470 #elif defined (IRIX6)
471 /****************************************************************************
472 try to get the disk space from disk quotas (IRIX 6.2 version)
473 ****************************************************************************/
475 #include <sys/quota.h>
476 #include <mntent.h>
478 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
480 uid_t euser_id;
481 int r;
482 struct dqblk D;
483 struct fs_disk_quota F;
484 SMB_STRUCT_STAT S;
485 FILE *fp;
486 struct mntent *mnt;
487 SMB_DEV_T devno;
488 int found;
490 /* find the block device file */
492 if ( sys_stat(path, &S, false) == -1 ) {
493 return(False) ;
496 devno = S.st_ex_dev ;
498 fp = setmntent(MOUNTED,"r");
499 found = False ;
501 while ((mnt = getmntent(fp))) {
502 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
503 continue ;
504 if (S.st_ex_dev == devno) {
505 found = True ;
506 break ;
509 endmntent(fp) ;
511 if (!found) {
512 return(False);
515 euser_id=geteuid();
516 become_root();
518 /* Use softlimit to determine disk space, except when it has been exceeded */
520 *bsize = 512;
522 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
524 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
526 unbecome_root();
528 if (r==-1)
529 return(False);
531 /* Use softlimit to determine disk space, except when it has been exceeded */
532 if (
533 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
534 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
535 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
536 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
539 *dfree = 0;
540 *dsize = D.dqb_curblocks;
542 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
544 return(False);
546 else
548 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
549 *dsize = D.dqb_bsoftlimit;
553 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
555 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
557 unbecome_root();
559 if (r==-1)
561 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
562 return(False);
565 /* No quota for this user. */
566 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
568 return(False);
571 /* Use softlimit to determine disk space, except when it has been exceeded */
572 if (
573 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
574 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
575 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
576 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
579 *dfree = 0;
580 *dsize = F.d_bcount;
582 else
584 *dfree = (F.d_blk_softlimit - F.d_bcount);
585 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
589 else
591 unbecome_root();
592 return(False);
595 return (True);
599 #else
601 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
602 #include <ufs/ufs/quota.h>
603 #include <machine/param.h>
604 #elif AIX
605 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
606 #include <jfs/quota.h>
607 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
608 #define dqb_curfiles dqb_curinodes
609 #define dqb_fhardlimit dqb_ihardlimit
610 #define dqb_fsoftlimit dqb_isoftlimit
611 #ifdef _AIXVERSION_530
612 #include <sys/statfs.h>
613 #include <sys/vmount.h>
614 #endif /* AIX 5.3 */
615 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
616 #include <sys/quota.h>
617 #include <devnm.h>
618 #endif
620 #if defined(__FreeBSD__) || defined(__DragonFly__)
622 #include <rpc/rpc.h>
623 #include <rpc/types.h>
624 #include <rpcsvc/rquota.h>
625 #ifdef HAVE_RPC_NETTYPE_H
626 #include <rpc/nettype.h>
627 #endif
628 #include <rpc/xdr.h>
630 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
632 int quotastat;
634 if (!xdr_int(xdrsp, &quotastat)) {
635 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
636 return 0;
638 gqr->status = quotastat;
640 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
641 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
642 return 0;
644 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
645 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
646 return 0;
648 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
649 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
650 return 0;
652 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
653 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
654 return 0;
656 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
657 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
658 return 0;
660 return (1);
663 /* Works on FreeBSD, too. :-) */
664 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
666 uid_t uid = euser_id;
667 struct dqblk D;
668 char *mnttype = nfspath;
669 CLIENT *clnt;
670 struct getquota_rslt gqr;
671 struct getquota_args args;
672 char *cutstr, *pathname, *host, *testpath;
673 int len;
674 static struct timeval timeout = {2,0};
675 enum clnt_stat clnt_stat;
676 bool ret = True;
678 *bsize = *dfree = *dsize = (uint64_t)0;
680 len=strcspn(mnttype, ":");
681 pathname=strstr(mnttype, ":");
682 cutstr = (char *) SMB_MALLOC(len+1);
683 if (!cutstr)
684 return False;
686 memset(cutstr, '\0', len+1);
687 host = strncat(cutstr,mnttype, sizeof(char) * len );
688 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
689 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
690 testpath=strchr_m(mnttype, ':');
691 args.gqa_pathp = testpath+1;
692 args.gqa_uid = uid;
694 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
696 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
697 ret = False;
698 goto out;
701 clnt->cl_auth = authunix_create_default();
702 DEBUG(9,("nfs_quotas: auth_success\n"));
704 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);
706 if (clnt_stat != RPC_SUCCESS) {
707 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
708 ret = False;
709 goto out;
713 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
714 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
715 * something sensible.
718 switch (gqr.status) {
719 case 0:
720 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
721 ret = False;
722 goto out;
724 case 1:
725 DEBUG(9,("nfs_quotas: Good quota data\n"));
726 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
727 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
728 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
729 break;
731 case 2:
732 case 3:
733 D.dqb_bsoftlimit = 1;
734 D.dqb_curblocks = 1;
735 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
736 break;
738 default:
739 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
740 break;
743 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",
744 gqr.status,
745 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
746 gqr.getquota_rslt_u.gqr_rquota.rq_active,
747 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
748 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
749 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
751 if (D.dqb_bsoftlimit == 0)
752 D.dqb_bsoftlimit = D.dqb_bhardlimit;
753 if (D.dqb_bsoftlimit == 0)
754 return False;
756 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
757 *dsize = D.dqb_bsoftlimit;
759 if (D.dqb_curblocks == 1)
760 *bsize = DEV_BSIZE;
762 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
763 *dfree = 0;
764 *dsize = D.dqb_curblocks;
765 } else
766 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
768 out:
770 if (clnt) {
771 if (clnt->cl_auth)
772 auth_destroy(clnt->cl_auth);
773 clnt_destroy(clnt);
776 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
778 SAFE_FREE(cutstr);
779 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
780 return ret;
783 #endif
785 /****************************************************************************
786 try to get the disk space from disk quotas - default version
787 ****************************************************************************/
789 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
791 int r;
792 struct dqblk D;
793 uid_t euser_id;
794 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
795 char dev_disk[256];
796 SMB_STRUCT_STAT S;
798 /* find the block device file */
800 #ifdef HPUX
801 /* Need to set the cache flag to 1 for HPUX. Seems
802 * to have a significant performance boost when
803 * lstat calls on /dev access this function.
805 if ((sys_stat(path, &S, false)<0)
806 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
807 #else
808 if ((sys_stat(path, &S, false)<0)
809 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
810 return (False);
811 #endif /* ifdef HPUX */
813 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
815 euser_id = geteuid();
817 #ifdef HPUX
818 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
819 save_re_uid();
820 if (set_re_uid() != 0) return False;
822 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
824 restore_re_uid();
825 #else
826 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
828 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
829 gid_t egrp_id;
830 #if defined(__FreeBSD__) || defined(__DragonFly__)
831 SMB_DEV_T devno;
832 struct statfs *mnts;
833 SMB_STRUCT_STAT st;
834 int mntsize, i;
836 if (sys_stat(path, &st, false) < 0)
837 return False;
838 devno = st.st_ex_dev;
840 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
841 if (mntsize <= 0)
842 return False;
844 for (i = 0; i < mntsize; i++) {
845 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
846 return False;
847 if (st.st_ex_dev == devno)
848 break;
850 if (i == mntsize)
851 return False;
852 #endif
854 become_root();
856 #if defined(__FreeBSD__) || defined(__DragonFly__)
857 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
858 bool retval;
859 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
860 unbecome_root();
861 return retval;
863 #endif
865 egrp_id = getegid();
866 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
868 /* As FreeBSD has group quotas, if getting the user
869 quota fails, try getting the group instead. */
870 if (r) {
871 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
874 unbecome_root();
876 #elif defined(AIX)
877 /* AIX has both USER and GROUP quotas:
878 Get the USER quota (ohnielse@fysik.dtu.dk) */
879 #ifdef _AIXVERSION_530
881 struct statfs statbuf;
882 quota64_t user_quota;
883 if (statfs(path,&statbuf) != 0)
884 return False;
885 if(statbuf.f_vfstype == MNT_J2)
887 /* For some reason we need to be root for jfs2 */
888 become_root();
889 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
890 unbecome_root();
891 /* Copy results to old struct to let the following code work as before */
892 D.dqb_curblocks = user_quota.bused;
893 D.dqb_bsoftlimit = user_quota.bsoft;
894 D.dqb_bhardlimit = user_quota.bhard;
895 D.dqb_curfiles = user_quota.iused;
896 D.dqb_fsoftlimit = user_quota.isoft;
897 D.dqb_fhardlimit = user_quota.ihard;
899 else if(statbuf.f_vfstype == MNT_JFS)
901 #endif /* AIX 5.3 */
902 save_re_uid();
903 if (set_re_uid() != 0)
904 return False;
905 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
906 restore_re_uid();
907 #ifdef _AIXVERSION_530
909 else
910 r = 1; /* Fail for other FS-types */
912 #endif /* AIX 5.3 */
913 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
914 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
915 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
916 #endif /* HPUX */
918 /* Use softlimit to determine disk space, except when it has been exceeded */
919 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
920 *bsize = DEV_BSIZE;
921 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
922 *bsize = 1024;
923 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
925 if (r)
927 if (errno == EDQUOT)
929 *dfree =0;
930 *dsize =D.dqb_curblocks;
931 return (True);
933 else return(False);
936 /* If softlimit is zero, set it equal to hardlimit.
939 if (D.dqb_bsoftlimit==0)
940 D.dqb_bsoftlimit = D.dqb_bhardlimit;
942 if (D.dqb_bsoftlimit==0)
943 return(False);
944 /* Use softlimit to determine disk space, except when it has been exceeded */
945 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
946 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
947 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
948 #endif
950 *dfree = 0;
951 *dsize = D.dqb_curblocks;
953 else {
954 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
955 *dsize = D.dqb_bsoftlimit;
957 return (True);
960 #endif
962 #if definedr(LINUX) || defined(SUNOS) || defined (__FreeBSD__) || defined(__DragonFly__)
963 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
965 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
966 return(0);
967 if (!xdr_int(xdrsp, &args->gqa_uid))
968 return(0);
969 return (1);
971 #endif
973 #if defined(VXFS_QUOTA)
975 /****************************************************************************
976 Try to get the disk space from Veritas disk quotas.
977 David Lee <T.D.Lee@durham.ac.uk> August 1999.
979 Background assumptions:
980 Potentially under many Operating Systems. Initially Solaris 2.
982 My guess is that Veritas is largely, though not entirely,
983 independent of OS. So I have separated it out.
985 There may be some details. For example, OS-specific "include" files.
987 It is understood that HPUX 10 somehow gets Veritas quotas without
988 any special effort; if so, this routine need not be compiled in.
989 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
991 Warning:
992 It is understood that Veritas do not publicly support this ioctl interface.
993 Rather their preference would be for the user (us) to call the native
994 OS and then for the OS itself to call through to the VxFS filesystem.
995 Presumably HPUX 10, see above, does this.
997 Hints for porting:
998 Add your OS to "IFLIST" below.
999 Get it to compile successfully:
1000 Almost certainly "include"s require attention: see SUNOS5.
1001 In the main code above, arrange for it to be called: see SUNOS5.
1002 Test!
1004 ****************************************************************************/
1006 /* "IFLIST"
1007 * This "if" is a list of ports:
1008 * if defined(OS1) || defined(OS2) || ...
1010 #if defined(SUNOS5)
1012 #if defined(SUNOS5)
1013 #include <sys/fs/vx_solaris.h>
1014 #endif
1015 #include <sys/fs/vx_machdep.h>
1016 #include <sys/fs/vx_layout.h>
1017 #include <sys/fs/vx_quota.h>
1018 #include <sys/fs/vx_aioctl.h>
1019 #include <sys/fs/vx_ioctl.h>
1021 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1023 uid_t user_id, euser_id;
1024 int ret;
1025 struct vx_dqblk D;
1026 struct vx_quotctl quotabuf;
1027 struct vx_genioctl genbuf;
1028 char *qfname;
1029 int file;
1032 * "name" may or may not include a trailing "/quotas".
1033 * Arranging consistency of calling here in "quotas.c" may not be easy and
1034 * it might be easier to examine and adjust it here.
1035 * Fortunately, VxFS seems not to mind at present.
1037 qfname = talloc_strdup(talloc_tos(), name);
1038 if (!qfname) {
1039 return false;
1041 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1043 euser_id = geteuid();
1044 set_effective_uid(0);
1046 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1047 if((file=open(qfname, O_RDONLY,0))<0) {
1048 set_effective_uid(euser_id);
1049 return(False);
1051 genbuf.ioc_cmd = VX_QUOTACTL;
1052 genbuf.ioc_up = (void *) &quotabuf;
1054 quotabuf.cmd = VX_GETQUOTA;
1055 quotabuf.uid = euser_id;
1056 quotabuf.addr = (caddr_t) &D;
1057 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1058 close(file);
1060 set_effective_uid(euser_id);
1062 if (ret < 0) {
1063 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1064 return(False);
1067 /* If softlimit is zero, set it equal to hardlimit.
1070 if (D.dqb_bsoftlimit==0)
1071 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1073 /* Use softlimit to determine disk space. A user exceeding the quota is told
1074 * that there's no space left. Writes might actually work for a bit if the
1075 * hardlimit is set higher than softlimit. Effectively the disk becomes
1076 * made of rubber latex and begins to expand to accommodate the user :-)
1078 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1079 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1080 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1082 if (D.dqb_bsoftlimit==0)
1083 return(False);
1084 *bsize = DEV_BSIZE;
1085 *dsize = D.dqb_bsoftlimit;
1087 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1088 *dfree = 0;
1089 *dsize = D.dqb_curblocks;
1090 } else
1091 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1093 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1094 path,(double)*bsize,(double)*dfree,(double)*dsize));
1096 return(True);
1099 #endif /* SUNOS5 || ... */
1101 #endif /* VXFS_QUOTA */
1103 #else /* WITH_QUOTAS */
1105 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1107 (*bsize) = 512; /* This value should be ignored */
1109 /* And just to be sure we set some values that hopefully */
1110 /* will be larger that any possible real-world value */
1111 (*dfree) = (uint64_t)-1;
1112 (*dsize) = (uint64_t)-1;
1114 /* As we have select not to use quotas, allways fail */
1115 return false;
1117 #endif /* WITH_QUOTAS */
1119 #else /* HAVE_SYS_QUOTAS */
1120 /* wrapper to the new sys_quota interface
1121 this file should be removed later
1123 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1125 int r;
1126 SMB_DISK_QUOTA D;
1127 unid_t id;
1129 id.uid = geteuid();
1131 ZERO_STRUCT(D);
1132 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1134 /* Use softlimit to determine disk space, except when it has been exceeded */
1135 *bsize = D.bsize;
1136 if (r == -1) {
1137 if (errno == EDQUOT) {
1138 *dfree =0;
1139 *dsize =D.curblocks;
1140 return (True);
1141 } else {
1142 goto try_group_quota;
1146 /* Use softlimit to determine disk space, except when it has been exceeded */
1147 if (
1148 (D.softlimit && D.curblocks >= D.softlimit) ||
1149 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1150 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1151 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1153 *dfree = 0;
1154 *dsize = D.curblocks;
1155 } else if (D.softlimit==0 && D.hardlimit==0) {
1156 goto try_group_quota;
1157 } else {
1158 if (D.softlimit == 0)
1159 D.softlimit = D.hardlimit;
1160 *dfree = D.softlimit - D.curblocks;
1161 *dsize = D.softlimit;
1164 return True;
1166 try_group_quota:
1167 id.gid = getegid();
1169 ZERO_STRUCT(D);
1170 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1172 /* Use softlimit to determine disk space, except when it has been exceeded */
1173 *bsize = D.bsize;
1174 if (r == -1) {
1175 if (errno == EDQUOT) {
1176 *dfree =0;
1177 *dsize =D.curblocks;
1178 return (True);
1179 } else {
1180 return False;
1184 /* Use softlimit to determine disk space, except when it has been exceeded */
1185 if (
1186 (D.softlimit && D.curblocks >= D.softlimit) ||
1187 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1188 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1189 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1191 *dfree = 0;
1192 *dsize = D.curblocks;
1193 } else if (D.softlimit==0 && D.hardlimit==0) {
1194 return False;
1195 } else {
1196 if (D.softlimit == 0)
1197 D.softlimit = D.hardlimit;
1198 *dfree = D.softlimit - D.curblocks;
1199 *dsize = D.softlimit;
1202 return (True);
1204 #endif /* HAVE_SYS_QUOTAS */