build: Remove Unicos support (quota in particular)
[Samba/gbeck.git] / source3 / smbd / quotas.c
blob10b05562af63dd90032c3ef2902976092762781d
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(SUNOS5) || defined(SUNOS4)
494 #include <fcntl.h>
495 #include <sys/param.h>
496 #if defined(SUNOS5)
497 #include <sys/fs/ufs_quota.h>
498 #include <sys/mnttab.h>
499 #include <sys/mntent.h>
500 #else /* defined(SUNOS4) */
501 #include <ufs/quota.h>
502 #include <mntent.h>
503 #endif
505 #if defined(SUNOS5)
507 /****************************************************************************
508 Allows querying of remote hosts for quotas on NFS mounted shares.
509 Supports normal NFS and AMD mounts.
510 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
511 ****************************************************************************/
513 #include <rpc/rpc.h>
514 #include <rpc/types.h>
515 #include <rpcsvc/rquota.h>
516 #include <rpc/nettype.h>
517 #include <rpc/xdr.h>
519 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
521 int quotastat;
523 if (!xdr_int(xdrsp, &quotastat)) {
524 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
525 return 0;
527 gqr->status = quotastat;
529 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
530 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
531 return 0;
533 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
534 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
535 return 0;
537 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
538 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
539 return 0;
541 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
542 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
543 return 0;
545 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
546 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
547 return 0;
549 return (1);
552 /* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
553 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
555 uid_t uid = euser_id;
556 struct dqblk D;
557 char *mnttype = nfspath;
558 CLIENT *clnt;
559 struct getquota_rslt gqr;
560 struct getquota_args args;
561 char *cutstr, *pathname, *host, *testpath;
562 int len;
563 static struct timeval timeout = {2,0};
564 enum clnt_stat clnt_stat;
565 bool ret = True;
567 *bsize = *dfree = *dsize = (uint64_t)0;
569 len=strcspn(mnttype, ":");
570 pathname=strstr(mnttype, ":");
571 cutstr = (char *) SMB_MALLOC(len+1);
572 if (!cutstr)
573 return False;
575 memset(cutstr, '\0', len+1);
576 host = strncat(cutstr,mnttype, sizeof(char) * len );
577 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
578 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
579 testpath=strchr_m(mnttype, ':');
580 args.gqa_pathp = testpath+1;
581 args.gqa_uid = uid;
583 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
585 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
586 ret = False;
587 goto out;
590 clnt->cl_auth = authunix_create_default();
591 DEBUG(9,("nfs_quotas: auth_success\n"));
593 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
595 if (clnt_stat != RPC_SUCCESS) {
596 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
597 ret = False;
598 goto out;
602 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
603 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
604 * something sensible.
607 switch (gqr.status) {
608 case 0:
609 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
610 ret = False;
611 goto out;
613 case 1:
614 DEBUG(9,("nfs_quotas: Good quota data\n"));
615 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
616 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
617 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
618 break;
620 case 2:
621 case 3:
622 D.dqb_bsoftlimit = 1;
623 D.dqb_curblocks = 1;
624 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
625 break;
627 default:
628 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
629 break;
632 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",
633 gqr.status,
634 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
635 gqr.getquota_rslt_u.gqr_rquota.rq_active,
636 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
637 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
638 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
640 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
641 *dsize = D.dqb_bsoftlimit;
643 if (D.dqb_curblocks == 1)
644 *bsize = 512;
646 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
647 *dfree = 0;
648 *dsize = D.dqb_curblocks;
649 } else
650 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
652 out:
654 if (clnt) {
655 if (clnt->cl_auth)
656 auth_destroy(clnt->cl_auth);
657 clnt_destroy(clnt);
660 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
662 SAFE_FREE(cutstr);
663 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
664 return ret;
666 #endif
668 /****************************************************************************
669 try to get the disk space from disk quotas (SunOS & Solaris2 version)
670 Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
671 ****************************************************************************/
673 bool disk_quotas(const char *path,
674 uint64_t *bsize,
675 uint64_t *dfree,
676 uint64_t *dsize)
678 uid_t euser_id;
679 int ret;
680 struct dqblk D;
681 #if defined(SUNOS5)
682 struct quotctl command;
683 int file;
684 struct mnttab mnt;
685 #else /* SunOS4 */
686 struct mntent *mnt;
687 #endif
688 char *name = NULL;
689 FILE *fd;
690 SMB_STRUCT_STAT sbuf;
691 SMB_DEV_T devno;
692 bool found = false;
694 euser_id = geteuid();
696 if (sys_stat(path, &sbuf, false) == -1) {
697 return false;
700 devno = sbuf.st_ex_dev ;
701 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
702 path, (unsigned int)devno));
703 #if defined(SUNOS5)
704 if ((fd = fopen(MNTTAB, "r")) == NULL) {
705 return false;
708 while (getmntent(fd, &mnt) == 0) {
709 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
710 continue;
713 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
714 mnt.mnt_mountp, (unsigned int)devno));
716 /* quotas are only on vxfs, UFS or NFS */
717 if ((sbuf.st_ex_dev == devno) && (
718 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
719 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
720 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
721 found = true;
722 name = talloc_asprintf(talloc_tos(),
723 "%s/quotas",
724 mnt.mnt_mountp);
725 break;
729 fclose(fd);
730 #else /* SunOS4 */
731 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
732 return false;
735 while ((mnt = getmntent(fd)) != NULL) {
736 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
737 continue;
739 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
740 mnt->mnt_dir,
741 (unsigned int)sbuf.st_ex_dev));
742 if (sbuf.st_ex_dev == devno) {
743 found = true;
744 name = talloc_strdup(talloc_tos(),
745 mnt->mnt_fsname);
746 break;
750 endmntent(fd);
751 #endif
752 if (!found) {
753 return false;
756 if (!name) {
757 return false;
759 become_root();
761 #if defined(SUNOS5)
762 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
763 bool retval;
764 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
765 mnt.mnt_special));
766 retval = nfs_quotas(mnt.mnt_special,
767 euser_id, bsize, dfree, dsize);
768 unbecome_root();
769 return retval;
772 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
773 if((file=open(name, O_RDONLY,0))<0) {
774 unbecome_root();
775 return false;
777 command.op = Q_GETQUOTA;
778 command.uid = euser_id;
779 command.addr = (caddr_t) &D;
780 ret = ioctl(file, Q_QUOTACTL, &command);
781 close(file);
782 #else
783 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
784 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
785 #endif
787 unbecome_root();
789 if (ret < 0) {
790 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
791 strerror(errno) ));
793 #if defined(SUNOS5) && defined(VXFS_QUOTA)
794 /* If normal quotactl() fails, try vxfs private calls */
795 set_effective_uid(euser_id);
796 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
797 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
798 bool retval;
799 retval = disk_quotas_vxfs(name, path,
800 bsize, dfree, dsize);
801 return retval;
803 #else
804 return false;
805 #endif
808 /* If softlimit is zero, set it equal to hardlimit.
811 if (D.dqb_bsoftlimit==0) {
812 D.dqb_bsoftlimit = D.dqb_bhardlimit;
815 /* Use softlimit to determine disk space. A user exceeding the quota
816 * is told that there's no space left. Writes might actually work for
817 * a bit if the hardlimit is set higher than softlimit. Effectively
818 * the disk becomes made of rubber latex and begins to expand to
819 * accommodate the user :-)
822 if (D.dqb_bsoftlimit==0)
823 return(False);
824 *bsize = DEV_BSIZE;
825 *dsize = D.dqb_bsoftlimit;
827 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
828 *dfree = 0;
829 *dsize = D.dqb_curblocks;
830 } else {
831 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
834 DEBUG(5,("disk_quotas for path \"%s\" returning "
835 "bsize %.0f, dfree %.0f, dsize %.0f\n",
836 path,(double)*bsize,(double)*dfree,(double)*dsize));
838 return true;
842 #elif defined(OSF1)
843 #include <ufs/quota.h>
845 /****************************************************************************
846 try to get the disk space from disk quotas - OSF1 version
847 ****************************************************************************/
849 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
851 int r, save_errno;
852 struct dqblk D;
853 SMB_STRUCT_STAT S;
854 uid_t euser_id;
857 * This code presumes that OSF1 will only
858 * give out quota info when the real uid
859 * matches the effective uid. JRA.
861 euser_id = geteuid();
862 save_re_uid();
863 if (set_re_uid() != 0) return False;
865 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
866 if (r) {
867 save_errno = errno;
870 restore_re_uid();
872 *bsize = DEV_BSIZE;
874 if (r)
876 if (save_errno == EDQUOT) /* disk quota exceeded */
878 *dfree = 0;
879 *dsize = D.dqb_curblocks;
880 return (True);
882 else
883 return (False);
886 /* If softlimit is zero, set it equal to hardlimit.
889 if (D.dqb_bsoftlimit==0)
890 D.dqb_bsoftlimit = D.dqb_bhardlimit;
892 /* Use softlimit to determine disk space, except when it has been exceeded */
894 if (D.dqb_bsoftlimit==0)
895 return(False);
897 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
898 *dfree = 0;
899 *dsize = D.dqb_curblocks;
900 } else {
901 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
902 *dsize = D.dqb_bsoftlimit;
904 return (True);
907 #elif defined (IRIX6)
908 /****************************************************************************
909 try to get the disk space from disk quotas (IRIX 6.2 version)
910 ****************************************************************************/
912 #include <sys/quota.h>
913 #include <mntent.h>
915 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
917 uid_t euser_id;
918 int r;
919 struct dqblk D;
920 struct fs_disk_quota F;
921 SMB_STRUCT_STAT S;
922 FILE *fp;
923 struct mntent *mnt;
924 SMB_DEV_T devno;
925 int found;
927 /* find the block device file */
929 if ( sys_stat(path, &S, false) == -1 ) {
930 return(False) ;
933 devno = S.st_ex_dev ;
935 fp = setmntent(MOUNTED,"r");
936 found = False ;
938 while ((mnt = getmntent(fp))) {
939 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
940 continue ;
941 if (S.st_ex_dev == devno) {
942 found = True ;
943 break ;
946 endmntent(fp) ;
948 if (!found) {
949 return(False);
952 euser_id=geteuid();
953 become_root();
955 /* Use softlimit to determine disk space, except when it has been exceeded */
957 *bsize = 512;
959 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
961 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
963 unbecome_root();
965 if (r==-1)
966 return(False);
968 /* Use softlimit to determine disk space, except when it has been exceeded */
969 if (
970 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
971 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
972 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
973 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
976 *dfree = 0;
977 *dsize = D.dqb_curblocks;
979 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
981 return(False);
983 else
985 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
986 *dsize = D.dqb_bsoftlimit;
990 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
992 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
994 unbecome_root();
996 if (r==-1)
998 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
999 return(False);
1002 /* No quota for this user. */
1003 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1005 return(False);
1008 /* Use softlimit to determine disk space, except when it has been exceeded */
1009 if (
1010 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1011 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1012 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1013 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1016 *dfree = 0;
1017 *dsize = F.d_bcount;
1019 else
1021 *dfree = (F.d_blk_softlimit - F.d_bcount);
1022 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1026 else
1028 unbecome_root();
1029 return(False);
1032 return (True);
1036 #else
1038 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1039 #include <ufs/ufs/quota.h>
1040 #include <machine/param.h>
1041 #elif AIX
1042 /* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1043 #include <jfs/quota.h>
1044 /* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1045 #define dqb_curfiles dqb_curinodes
1046 #define dqb_fhardlimit dqb_ihardlimit
1047 #define dqb_fsoftlimit dqb_isoftlimit
1048 #ifdef _AIXVERSION_530
1049 #include <sys/statfs.h>
1050 #include <sys/vmount.h>
1051 #endif /* AIX 5.3 */
1052 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1053 #include <sys/quota.h>
1054 #include <devnm.h>
1055 #endif
1057 #if defined(__FreeBSD__) || defined(__DragonFly__)
1059 #include <rpc/rpc.h>
1060 #include <rpc/types.h>
1061 #include <rpcsvc/rquota.h>
1062 #ifdef HAVE_RPC_NETTYPE_H
1063 #include <rpc/nettype.h>
1064 #endif
1065 #include <rpc/xdr.h>
1067 static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1069 int quotastat;
1071 if (!xdr_int(xdrsp, &quotastat)) {
1072 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1073 return 0;
1075 gqr->status = quotastat;
1077 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1078 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1079 return 0;
1081 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1082 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1083 return 0;
1085 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1086 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1087 return 0;
1089 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1090 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1091 return 0;
1093 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1094 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1095 return 0;
1097 return (1);
1100 /* Works on FreeBSD, too. :-) */
1101 static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1103 uid_t uid = euser_id;
1104 struct dqblk D;
1105 char *mnttype = nfspath;
1106 CLIENT *clnt;
1107 struct getquota_rslt gqr;
1108 struct getquota_args args;
1109 char *cutstr, *pathname, *host, *testpath;
1110 int len;
1111 static struct timeval timeout = {2,0};
1112 enum clnt_stat clnt_stat;
1113 bool ret = True;
1115 *bsize = *dfree = *dsize = (uint64_t)0;
1117 len=strcspn(mnttype, ":");
1118 pathname=strstr(mnttype, ":");
1119 cutstr = (char *) SMB_MALLOC(len+1);
1120 if (!cutstr)
1121 return False;
1123 memset(cutstr, '\0', len+1);
1124 host = strncat(cutstr,mnttype, sizeof(char) * len );
1125 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1126 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1127 testpath=strchr_m(mnttype, ':');
1128 args.gqa_pathp = testpath+1;
1129 args.gqa_uid = uid;
1131 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1133 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1134 ret = False;
1135 goto out;
1138 clnt->cl_auth = authunix_create_default();
1139 DEBUG(9,("nfs_quotas: auth_success\n"));
1141 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);
1143 if (clnt_stat != RPC_SUCCESS) {
1144 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1145 ret = False;
1146 goto out;
1150 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1151 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1152 * something sensible.
1155 switch (gqr.status) {
1156 case 0:
1157 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1158 ret = False;
1159 goto out;
1161 case 1:
1162 DEBUG(9,("nfs_quotas: Good quota data\n"));
1163 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1164 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1165 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1166 break;
1168 case 2:
1169 case 3:
1170 D.dqb_bsoftlimit = 1;
1171 D.dqb_curblocks = 1;
1172 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1173 break;
1175 default:
1176 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1177 break;
1180 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",
1181 gqr.status,
1182 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1183 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1184 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1185 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1186 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1188 if (D.dqb_bsoftlimit == 0)
1189 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1190 if (D.dqb_bsoftlimit == 0)
1191 return False;
1193 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1194 *dsize = D.dqb_bsoftlimit;
1196 if (D.dqb_curblocks == 1)
1197 *bsize = DEV_BSIZE;
1199 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1200 *dfree = 0;
1201 *dsize = D.dqb_curblocks;
1202 } else
1203 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1205 out:
1207 if (clnt) {
1208 if (clnt->cl_auth)
1209 auth_destroy(clnt->cl_auth);
1210 clnt_destroy(clnt);
1213 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1215 SAFE_FREE(cutstr);
1216 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1217 return ret;
1220 #endif
1222 /****************************************************************************
1223 try to get the disk space from disk quotas - default version
1224 ****************************************************************************/
1226 bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1228 int r;
1229 struct dqblk D;
1230 uid_t euser_id;
1231 #if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1232 char dev_disk[256];
1233 SMB_STRUCT_STAT S;
1235 /* find the block device file */
1237 #ifdef HPUX
1238 /* Need to set the cache flag to 1 for HPUX. Seems
1239 * to have a significant performance boost when
1240 * lstat calls on /dev access this function.
1242 if ((sys_stat(path, &S, false)<0)
1243 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1244 #else
1245 if ((sys_stat(path, &S, false)<0)
1246 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1247 return (False);
1248 #endif /* ifdef HPUX */
1250 #endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1252 euser_id = geteuid();
1254 #ifdef HPUX
1255 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1256 save_re_uid();
1257 if (set_re_uid() != 0) return False;
1259 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1261 restore_re_uid();
1262 #else
1263 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1265 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1266 gid_t egrp_id;
1267 #if defined(__FreeBSD__) || defined(__DragonFly__)
1268 SMB_DEV_T devno;
1269 struct statfs *mnts;
1270 SMB_STRUCT_STAT st;
1271 int mntsize, i;
1273 if (sys_stat(path, &st, false) < 0)
1274 return False;
1275 devno = st.st_ex_dev;
1277 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1278 if (mntsize <= 0)
1279 return False;
1281 for (i = 0; i < mntsize; i++) {
1282 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1283 return False;
1284 if (st.st_ex_dev == devno)
1285 break;
1287 if (i == mntsize)
1288 return False;
1289 #endif
1291 become_root();
1293 #if defined(__FreeBSD__) || defined(__DragonFly__)
1294 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1295 bool retval;
1296 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1297 unbecome_root();
1298 return retval;
1300 #endif
1302 egrp_id = getegid();
1303 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1305 /* As FreeBSD has group quotas, if getting the user
1306 quota fails, try getting the group instead. */
1307 if (r) {
1308 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1311 unbecome_root();
1313 #elif defined(AIX)
1314 /* AIX has both USER and GROUP quotas:
1315 Get the USER quota (ohnielse@fysik.dtu.dk) */
1316 #ifdef _AIXVERSION_530
1318 struct statfs statbuf;
1319 quota64_t user_quota;
1320 if (statfs(path,&statbuf) != 0)
1321 return False;
1322 if(statbuf.f_vfstype == MNT_J2)
1324 /* For some reason we need to be root for jfs2 */
1325 become_root();
1326 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1327 unbecome_root();
1328 /* Copy results to old struct to let the following code work as before */
1329 D.dqb_curblocks = user_quota.bused;
1330 D.dqb_bsoftlimit = user_quota.bsoft;
1331 D.dqb_bhardlimit = user_quota.bhard;
1332 D.dqb_curfiles = user_quota.iused;
1333 D.dqb_fsoftlimit = user_quota.isoft;
1334 D.dqb_fhardlimit = user_quota.ihard;
1336 else if(statbuf.f_vfstype == MNT_JFS)
1338 #endif /* AIX 5.3 */
1339 save_re_uid();
1340 if (set_re_uid() != 0)
1341 return False;
1342 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1343 restore_re_uid();
1344 #ifdef _AIXVERSION_530
1346 else
1347 r = 1; /* Fail for other FS-types */
1349 #endif /* AIX 5.3 */
1350 #else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1351 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1352 #endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1353 #endif /* HPUX */
1355 /* Use softlimit to determine disk space, except when it has been exceeded */
1356 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1357 *bsize = DEV_BSIZE;
1358 #else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1359 *bsize = 1024;
1360 #endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1362 if (r)
1364 if (errno == EDQUOT)
1366 *dfree =0;
1367 *dsize =D.dqb_curblocks;
1368 return (True);
1370 else return(False);
1373 /* If softlimit is zero, set it equal to hardlimit.
1376 if (D.dqb_bsoftlimit==0)
1377 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1379 if (D.dqb_bsoftlimit==0)
1380 return(False);
1381 /* Use softlimit to determine disk space, except when it has been exceeded */
1382 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1383 #if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1384 ||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1385 #endif
1387 *dfree = 0;
1388 *dsize = D.dqb_curblocks;
1390 else {
1391 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1392 *dsize = D.dqb_bsoftlimit;
1394 return (True);
1397 #endif
1399 #if definedr(LINUX) || defined(SUNOS) || defined (__FreeBSD__) || defined(__DragonFly__)
1400 static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1402 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1403 return(0);
1404 if (!xdr_int(xdrsp, &args->gqa_uid))
1405 return(0);
1406 return (1);
1408 #endif
1410 #if defined(VXFS_QUOTA)
1412 /****************************************************************************
1413 Try to get the disk space from Veritas disk quotas.
1414 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1416 Background assumptions:
1417 Potentially under many Operating Systems. Initially Solaris 2.
1419 My guess is that Veritas is largely, though not entirely,
1420 independent of OS. So I have separated it out.
1422 There may be some details. For example, OS-specific "include" files.
1424 It is understood that HPUX 10 somehow gets Veritas quotas without
1425 any special effort; if so, this routine need not be compiled in.
1426 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1428 Warning:
1429 It is understood that Veritas do not publicly support this ioctl interface.
1430 Rather their preference would be for the user (us) to call the native
1431 OS and then for the OS itself to call through to the VxFS filesystem.
1432 Presumably HPUX 10, see above, does this.
1434 Hints for porting:
1435 Add your OS to "IFLIST" below.
1436 Get it to compile successfully:
1437 Almost certainly "include"s require attention: see SUNOS5.
1438 In the main code above, arrange for it to be called: see SUNOS5.
1439 Test!
1441 ****************************************************************************/
1443 /* "IFLIST"
1444 * This "if" is a list of ports:
1445 * if defined(OS1) || defined(OS2) || ...
1447 #if defined(SUNOS5)
1449 #if defined(SUNOS5)
1450 #include <sys/fs/vx_solaris.h>
1451 #endif
1452 #include <sys/fs/vx_machdep.h>
1453 #include <sys/fs/vx_layout.h>
1454 #include <sys/fs/vx_quota.h>
1455 #include <sys/fs/vx_aioctl.h>
1456 #include <sys/fs/vx_ioctl.h>
1458 bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1460 uid_t user_id, euser_id;
1461 int ret;
1462 struct vx_dqblk D;
1463 struct vx_quotctl quotabuf;
1464 struct vx_genioctl genbuf;
1465 char *qfname;
1466 int file;
1469 * "name" may or may not include a trailing "/quotas".
1470 * Arranging consistency of calling here in "quotas.c" may not be easy and
1471 * it might be easier to examine and adjust it here.
1472 * Fortunately, VxFS seems not to mind at present.
1474 qfname = talloc_strdup(talloc_tos(), name);
1475 if (!qfname) {
1476 return false;
1478 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1480 euser_id = geteuid();
1481 set_effective_uid(0);
1483 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1484 if((file=open(qfname, O_RDONLY,0))<0) {
1485 set_effective_uid(euser_id);
1486 return(False);
1488 genbuf.ioc_cmd = VX_QUOTACTL;
1489 genbuf.ioc_up = (void *) &quotabuf;
1491 quotabuf.cmd = VX_GETQUOTA;
1492 quotabuf.uid = euser_id;
1493 quotabuf.addr = (caddr_t) &D;
1494 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1495 close(file);
1497 set_effective_uid(euser_id);
1499 if (ret < 0) {
1500 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1501 return(False);
1504 /* If softlimit is zero, set it equal to hardlimit.
1507 if (D.dqb_bsoftlimit==0)
1508 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1510 /* Use softlimit to determine disk space. A user exceeding the quota is told
1511 * that there's no space left. Writes might actually work for a bit if the
1512 * hardlimit is set higher than softlimit. Effectively the disk becomes
1513 * made of rubber latex and begins to expand to accommodate the user :-)
1515 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1516 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1517 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1519 if (D.dqb_bsoftlimit==0)
1520 return(False);
1521 *bsize = DEV_BSIZE;
1522 *dsize = D.dqb_bsoftlimit;
1524 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1525 *dfree = 0;
1526 *dsize = D.dqb_curblocks;
1527 } else
1528 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1530 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1531 path,(double)*bsize,(double)*dfree,(double)*dsize));
1533 return(True);
1536 #endif /* SUNOS5 || ... */
1538 #endif /* VXFS_QUOTA */
1540 #else /* WITH_QUOTAS */
1542 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1544 (*bsize) = 512; /* This value should be ignored */
1546 /* And just to be sure we set some values that hopefully */
1547 /* will be larger that any possible real-world value */
1548 (*dfree) = (uint64_t)-1;
1549 (*dsize) = (uint64_t)-1;
1551 /* As we have select not to use quotas, allways fail */
1552 return false;
1554 #endif /* WITH_QUOTAS */
1556 #else /* HAVE_SYS_QUOTAS */
1557 /* wrapper to the new sys_quota interface
1558 this file should be removed later
1560 bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1562 int r;
1563 SMB_DISK_QUOTA D;
1564 unid_t id;
1566 id.uid = geteuid();
1568 ZERO_STRUCT(D);
1569 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1571 /* Use softlimit to determine disk space, except when it has been exceeded */
1572 *bsize = D.bsize;
1573 if (r == -1) {
1574 if (errno == EDQUOT) {
1575 *dfree =0;
1576 *dsize =D.curblocks;
1577 return (True);
1578 } else {
1579 goto try_group_quota;
1583 /* Use softlimit to determine disk space, except when it has been exceeded */
1584 if (
1585 (D.softlimit && D.curblocks >= D.softlimit) ||
1586 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1587 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1588 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1590 *dfree = 0;
1591 *dsize = D.curblocks;
1592 } else if (D.softlimit==0 && D.hardlimit==0) {
1593 goto try_group_quota;
1594 } else {
1595 if (D.softlimit == 0)
1596 D.softlimit = D.hardlimit;
1597 *dfree = D.softlimit - D.curblocks;
1598 *dsize = D.softlimit;
1601 return True;
1603 try_group_quota:
1604 id.gid = getegid();
1606 ZERO_STRUCT(D);
1607 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1609 /* Use softlimit to determine disk space, except when it has been exceeded */
1610 *bsize = D.bsize;
1611 if (r == -1) {
1612 if (errno == EDQUOT) {
1613 *dfree =0;
1614 *dsize =D.curblocks;
1615 return (True);
1616 } else {
1617 return False;
1621 /* Use softlimit to determine disk space, except when it has been exceeded */
1622 if (
1623 (D.softlimit && D.curblocks >= D.softlimit) ||
1624 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1625 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1626 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1628 *dfree = 0;
1629 *dsize = D.curblocks;
1630 } else if (D.softlimit==0 && D.hardlimit==0) {
1631 return False;
1632 } else {
1633 if (D.softlimit == 0)
1634 D.softlimit = D.hardlimit;
1635 *dfree = D.softlimit - D.curblocks;
1636 *dsize = D.softlimit;
1639 return (True);
1641 #endif /* HAVE_SYS_QUOTAS */