source: trunk/server/source3/smbd/quotas.c@ 987

Last change on this file since 987 was 751, checked in by Silvan Scherrer, 13 years ago

Samba Server: updated trunk to 3.6.9

File size: 46.1 KB
Line 
1/*
2 Unix SMB/CIFS implementation.
3 support for quotas
4 Copyright (C) Andrew Tridgell 1992-1998
5
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.
10
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.
15
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/>.
18*/
19
20
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 :-(
25 */
26
27#include "includes.h"
28#include "smbd/smbd.h"
29#include "system/filesys.h"
30
31#undef DBGC_CLASS
32#define DBGC_CLASS DBGC_QUOTA
33
34#ifndef HAVE_SYS_QUOTAS
35
36/* just a quick hack because sysquotas.h is included before linux/quota.h */
37#ifdef QUOTABLOCK_SIZE
38#undef QUOTABLOCK_SIZE
39#endif
40
41#ifdef WITH_QUOTAS
42
43#if defined(VXFS_QUOTA)
44
45/*
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>
49 */
50bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize);
51
52#endif /* VXFS_QUOTA */
53
54#ifdef LINUX
55
56#include <sys/types.h>
57#include <mntent.h>
58
59/*
60 * This shouldn't be neccessary - it should be /usr/include/sys/quota.h
61 * So we include all the files has *should* be in the system into a large,
62 * grungy samba_linux_quoatas.h Sometimes I *hate* Linux :-). JRA.
63 */
64
65#include "samba_linux_quota.h"
66
67typedef struct _LINUX_SMB_DISK_QUOTA {
68 uint64_t bsize;
69 uint64_t hardlimit; /* In bsize units. */
70 uint64_t softlimit; /* In bsize units. */
71 uint64_t curblocks; /* In bsize units. */
72 uint64_t ihardlimit; /* inode hard limit. */
73 uint64_t isoftlimit; /* inode soft limit. */
74 uint64_t curinodes; /* Current used inodes. */
75} LINUX_SMB_DISK_QUOTA;
76
77
78/*
79 * nfs quota support
80 * (essentially taken from FreeBSD / SUNOS5 section)
81 */
82#include <rpc/rpc.h>
83#include <rpc/types.h>
84#include <rpcsvc/rquota.h>
85#ifdef HAVE_RPC_NETTYPE_H
86#include <rpc/nettype.h>
87#endif
88#include <rpc/xdr.h>
89
90static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
91{
92 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
93 return(0);
94 if (!xdr_int(xdrsp, &args->gqa_uid))
95 return(0);
96 return (1);
97}
98
99static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
100{
101 int quotastat;
102
103 if (!xdr_int(xdrsp, &quotastat)) {
104 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
105 return 0;
106 }
107 gqr->status = quotastat;
108
109 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
110 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
111 return 0;
112 }
113 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
114 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
115 return 0;
116 }
117 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
118 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
119 return 0;
120 }
121 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
122 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
123 return 0;
124 }
125 if (!xdr_int(xdrsp, (int *)&gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
126 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
127 return 0;
128 }
129 return 1;
130}
131
132static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize,
133 uint64_t *dfree, uint64_t *dsize)
134{
135 uid_t uid = euser_id;
136 LINUX_SMB_DISK_QUOTA D;
137 char *mnttype = nfspath;
138 CLIENT *clnt;
139 struct getquota_rslt gqr;
140 struct getquota_args args;
141 char *cutstr, *pathname, *host, *testpath;
142 int len;
143 static struct timeval timeout = {2,0};
144 enum clnt_stat clnt_stat;
145 bool ret = True;
146
147 *bsize = *dfree = *dsize = (uint64_t)0;
148
149 len=strcspn(mnttype, ":");
150 pathname=strstr(mnttype, ":");
151 cutstr = (char *) SMB_MALLOC(len+1);
152 if (!cutstr)
153 return False;
154
155 memset(cutstr, '\0', len+1);
156 host = strncat(cutstr,mnttype, sizeof(char) * len );
157 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
158 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
159 testpath=strchr_m(mnttype, ':');
160 args.gqa_pathp = testpath+1;
161 args.gqa_uid = uid;
162
163 DEBUG(5, ("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers "
164 "\"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS,
165 "udp"));
166
167 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
168 ret = False;
169 goto out;
170 }
171
172 clnt->cl_auth = authunix_create_default();
173 DEBUG(9,("nfs_quotas: auth_success\n"));
174
175 clnt_stat=clnt_call(clnt,
176 RQUOTAPROC_GETQUOTA,
177 (const xdrproc_t)my_xdr_getquota_args,
178 (caddr_t)&args,
179 (const xdrproc_t)my_xdr_getquota_rslt,
180 (caddr_t)&gqr, timeout);
181
182 if (clnt_stat != RPC_SUCCESS) {
183 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
184 ret = False;
185 goto out;
186 }
187
188 /*
189 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
190 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
191 * something sensible.
192 */
193
194 switch (gqr.status) {
195 case 0:
196 DEBUG(9, ("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n",
197 gqr.status));
198 ret = False;
199 goto out;
200
201 case 1:
202 DEBUG(9,("nfs_quotas: Good quota data\n"));
203 D.softlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
204 D.hardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
205 D.curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
206 break;
207
208 case 2:
209 case 3:
210 D.softlimit = 1;
211 D.curblocks = 1;
212 DEBUG(9, ("nfs_quotas: Remote Quotas returned \"%i\" \n",
213 gqr.status));
214 break;
215
216 default:
217 DEBUG(9, ("nfs_quotas: Remote Quotas Questionable! "
218 "Error \"%i\" \n", gqr.status));
219 break;
220 }
221
222 DEBUG(10, ("nfs_quotas: Let`s look at D a bit closer... "
223 "status \"%i\" bsize \"%i\" active? \"%i\" bhard "
224 "\"%i\" bsoft \"%i\" curb \"%i\" \n",
225 gqr.status,
226 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
227 gqr.getquota_rslt_u.gqr_rquota.rq_active,
228 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
229 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
230 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
231
232 if (D.softlimit == 0)
233 D.softlimit = D.hardlimit;
234 if (D.softlimit == 0)
235 return False;
236
237 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
238 *dsize = D.softlimit;
239
240 if (D.curblocks == 1)
241 *bsize = DEV_BSIZE;
242
243 if (D.curblocks > D.softlimit) {
244 *dfree = 0;
245 *dsize = D.curblocks;
246 } else
247 *dfree = D.softlimit - D.curblocks;
248
249 out:
250
251 if (clnt) {
252 if (clnt->cl_auth)
253 auth_destroy(clnt->cl_auth);
254 clnt_destroy(clnt);
255 }
256
257 DEBUG(5, ("nfs_quotas: For path \"%s\" returning "
258 "bsize %.0f, dfree %.0f, dsize %.0f\n",
259 args.gqa_pathp, (double)*bsize, (double)*dfree,
260 (double)*dsize));
261
262 SAFE_FREE(cutstr);
263 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
264 return ret;
265}
266
267/* end of nfs quota section */
268
269#ifdef HAVE_LINUX_DQBLK_XFS_H
270#include <linux/dqblk_xfs.h>
271
272/****************************************************************************
273 Abstract out the XFS Quota Manager quota get call.
274****************************************************************************/
275
276static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
277{
278 struct fs_disk_quota D;
279 int ret;
280
281 ZERO_STRUCT(D);
282
283 ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
284
285 if (ret)
286 ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
287
288 if (ret)
289 return ret;
290
291 dp->bsize = (uint64_t)512;
292 dp->softlimit = (uint64_t)D.d_blk_softlimit;
293 dp->hardlimit = (uint64_t)D.d_blk_hardlimit;
294 dp->ihardlimit = (uint64_t)D.d_ino_hardlimit;
295 dp->isoftlimit = (uint64_t)D.d_ino_softlimit;
296 dp->curinodes = (uint64_t)D.d_icount;
297 dp->curblocks = (uint64_t)D.d_bcount;
298
299 return ret;
300}
301#else
302static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
303{
304 DEBUG(0,("XFS quota support not available\n"));
305 errno = ENOSYS;
306 return -1;
307}
308#endif
309
310
311/****************************************************************************
312 Abstract out the old and new Linux quota get calls.
313****************************************************************************/
314
315static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
316{
317 struct v1_kern_dqblk D;
318 int ret;
319
320 ZERO_STRUCT(D);
321
322 ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
323
324 if (ret && errno != EDQUOT)
325 ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
326
327 if (ret && errno != EDQUOT)
328 return ret;
329
330 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
331 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
332 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
333 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
334 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
335 dp->curinodes = (uint64_t)D.dqb_curinodes;
336 dp->curblocks = (uint64_t)D.dqb_curblocks;
337
338 return ret;
339}
340
341static int get_smb_linux_v2_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
342{
343 struct v2_kern_dqblk D;
344 int ret;
345
346 ZERO_STRUCT(D);
347
348 ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
349
350 if (ret && errno != EDQUOT)
351 ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
352
353 if (ret && errno != EDQUOT)
354 return ret;
355
356 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
357 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
358 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
359 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
360 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
361 dp->curinodes = (uint64_t)D.dqb_curinodes;
362 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
363
364 return ret;
365}
366
367/****************************************************************************
368 Brand-new generic quota interface.
369****************************************************************************/
370
371static int get_smb_linux_gen_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
372{
373 struct if_dqblk D;
374 int ret;
375
376 ZERO_STRUCT(D);
377
378 ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
379
380 if (ret && errno != EDQUOT)
381 ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
382
383 if (ret && errno != EDQUOT)
384 return ret;
385
386 dp->bsize = (uint64_t)QUOTABLOCK_SIZE;
387 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
388 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
389 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
390 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
391 dp->curinodes = (uint64_t)D.dqb_curinodes;
392 dp->curblocks = ((uint64_t)D.dqb_curspace) / dp->bsize;
393
394 return ret;
395}
396
397/****************************************************************************
398 Try to get the disk space from disk quotas (LINUX version).
399****************************************************************************/
400
401bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
402{
403 int r;
404 SMB_STRUCT_STAT S;
405 FILE *fp;
406 LINUX_SMB_DISK_QUOTA D;
407 struct mntent *mnt;
408 SMB_DEV_T devno;
409 int found;
410 uid_t euser_id;
411 gid_t egrp_id;
412
413 ZERO_STRUCT(D);
414
415 euser_id = geteuid();
416 egrp_id = getegid();
417
418 /* find the block device file */
419
420 if (sys_stat(path, &S, false) == -1 )
421 return(False) ;
422
423 devno = S.st_ex_dev ;
424
425 if ((fp = setmntent(MOUNTED,"r")) == NULL)
426 return(False) ;
427
428 found = False ;
429
430 while ((mnt = getmntent(fp))) {
431 if (sys_stat(mnt->mnt_dir, &S, false) == -1)
432 continue ;
433
434 if (S.st_ex_dev == devno) {
435 found = True ;
436 break;
437 }
438 }
439
440 endmntent(fp) ;
441
442 if (!found)
443 return(False);
444
445 become_root();
446
447 if (strcmp(mnt->mnt_type, "nfs") == 0) {
448 bool retval;
449 retval = nfs_quotas(mnt->mnt_fsname , euser_id, bsize, dfree, dsize);
450 unbecome_root();
451 return retval;
452 }
453
454 if (strcmp(mnt->mnt_type, "xfs")==0) {
455 r=get_smb_linux_xfs_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
456 } else {
457 r=get_smb_linux_gen_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
458 if (r == -1 && errno != EDQUOT) {
459 r=get_smb_linux_v2_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
460 if (r == -1 && errno != EDQUOT)
461 r=get_smb_linux_v1_quota(mnt->mnt_fsname, euser_id, egrp_id, &D);
462 }
463 }
464
465 unbecome_root();
466
467 /* Use softlimit to determine disk space, except when it has been exceeded */
468 *bsize = D.bsize;
469 if (r == -1) {
470 if (errno == EDQUOT) {
471 *dfree =0;
472 *dsize =D.curblocks;
473 return (True);
474 } else {
475 return(False);
476 }
477 }
478
479 /* Use softlimit to determine disk space, except when it has been exceeded */
480 if (
481 (D.softlimit && D.curblocks >= D.softlimit) ||
482 (D.hardlimit && D.curblocks >= D.hardlimit) ||
483 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
484 (D.ihardlimit && D.curinodes>=D.ihardlimit)
485 ) {
486 *dfree = 0;
487 *dsize = D.curblocks;
488 } else if (D.softlimit==0 && D.hardlimit==0) {
489 return(False);
490 } else {
491 if (D.softlimit == 0)
492 D.softlimit = D.hardlimit;
493 *dfree = D.softlimit - D.curblocks;
494 *dsize = D.softlimit;
495 }
496
497 return (True);
498}
499
500#elif defined(CRAY)
501
502#include <sys/quota.h>
503#include <mntent.h>
504
505/****************************************************************************
506try to get the disk space from disk quotas (CRAY VERSION)
507****************************************************************************/
508
509bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
510{
511 struct mntent *mnt;
512 FILE *fd;
513 SMB_STRUCT_STAT sbuf;
514 SMB_DEV_T devno ;
515 struct q_request request ;
516 struct qf_header header ;
517 int quota_default = 0 ;
518 bool found = false;
519
520 if (sys_stat(path, &sbuf, false) == -1) {
521 return false;
522 }
523
524 devno = sbuf.st_ex_dev ;
525
526 if ((fd = setmntent(KMTAB)) == NULL) {
527 return false;
528 }
529
530 while ((mnt = getmntent(fd)) != NULL) {
531 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
532 continue;
533 }
534 if (sbuf.st_ex_dev == devno) {
535 found = frue ;
536 break;
537 }
538 }
539
540 name = talloc_strdup(talloc_tos(), mnt->mnt_dir);
541 endmntent(fd);
542 if (!found) {
543 return false;
544 }
545
546 if (!name) {
547 return false;
548 }
549
550 request.qf_magic = QF_MAGIC ;
551 request.qf_entry.id = geteuid() ;
552
553 if (quotactl(name, Q_GETQUOTA, &request) == -1) {
554 return false;
555 }
556
557 if (!request.user) {
558 return False;
559 }
560
561 if (request.qf_entry.user_q.f_quota == QFV_DEFAULT) {
562 if (!quota_default) {
563 if (quotactl(name, Q_GETHEADER, &header) == -1) {
564 return false;
565 } else {
566 quota_default = header.user_h.def_fq;
567 }
568 }
569 *dfree = quota_default;
570 } else if (request.qf_entry.user_q.f_quota == QFV_PREVENT) {
571 *dfree = 0;
572 } else {
573 *dfree = request.qf_entry.user_q.f_quota;
574 }
575
576 *dsize = request.qf_entry.user_q.f_use;
577
578 if (*dfree < *dsize) {
579 *dfree = 0;
580 } else {
581 *dfree -= *dsize;
582 }
583
584 *bsize = 4096 ; /* Cray blocksize */
585 return true;
586}
587
588
589#elif defined(SUNOS5) || defined(SUNOS4)
590
591#include <fcntl.h>
592#include <sys/param.h>
593#if defined(SUNOS5)
594#include <sys/fs/ufs_quota.h>
595#include <sys/mnttab.h>
596#include <sys/mntent.h>
597#else /* defined(SUNOS4) */
598#include <ufs/quota.h>
599#include <mntent.h>
600#endif
601
602#if defined(SUNOS5)
603
604/****************************************************************************
605 Allows querying of remote hosts for quotas on NFS mounted shares.
606 Supports normal NFS and AMD mounts.
607 Alan Romeril <a.romeril@ic.ac.uk> July 2K.
608****************************************************************************/
609
610#include <rpc/rpc.h>
611#include <rpc/types.h>
612#include <rpcsvc/rquota.h>
613#include <rpc/nettype.h>
614#include <rpc/xdr.h>
615
616static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
617{
618 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
619 return(0);
620 if (!xdr_int(xdrsp, &args->gqa_uid))
621 return(0);
622 return (1);
623}
624
625static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
626{
627 int quotastat;
628
629 if (!xdr_int(xdrsp, &quotastat)) {
630 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
631 return 0;
632 }
633 gqr->status = quotastat;
634
635 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
636 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
637 return 0;
638 }
639 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
640 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
641 return 0;
642 }
643 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
644 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
645 return 0;
646 }
647 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
648 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
649 return 0;
650 }
651 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
652 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
653 return 0;
654 }
655 return (1);
656}
657
658/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
659static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
660{
661 uid_t uid = euser_id;
662 struct dqblk D;
663 char *mnttype = nfspath;
664 CLIENT *clnt;
665 struct getquota_rslt gqr;
666 struct getquota_args args;
667 char *cutstr, *pathname, *host, *testpath;
668 int len;
669 static struct timeval timeout = {2,0};
670 enum clnt_stat clnt_stat;
671 bool ret = True;
672
673 *bsize = *dfree = *dsize = (uint64_t)0;
674
675 len=strcspn(mnttype, ":");
676 pathname=strstr(mnttype, ":");
677 cutstr = (char *) SMB_MALLOC(len+1);
678 if (!cutstr)
679 return False;
680
681 memset(cutstr, '\0', len+1);
682 host = strncat(cutstr,mnttype, sizeof(char) * len );
683 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
684 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
685 testpath=strchr_m(mnttype, ':');
686 args.gqa_pathp = testpath+1;
687 args.gqa_uid = uid;
688
689 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
690
691 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
692 ret = False;
693 goto out;
694 }
695
696 clnt->cl_auth = authunix_create_default();
697 DEBUG(9,("nfs_quotas: auth_success\n"));
698
699 clnt_stat=clnt_call(clnt, RQUOTAPROC_GETQUOTA, my_xdr_getquota_args, (caddr_t)&args, my_xdr_getquota_rslt, (caddr_t)&gqr, timeout);
700
701 if (clnt_stat != RPC_SUCCESS) {
702 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
703 ret = False;
704 goto out;
705 }
706
707 /*
708 * gqr.status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
709 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
710 * something sensible.
711 */
712
713 switch (gqr.status) {
714 case 0:
715 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
716 ret = False;
717 goto out;
718
719 case 1:
720 DEBUG(9,("nfs_quotas: Good quota data\n"));
721 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
722 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
723 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
724 break;
725
726 case 2:
727 case 3:
728 D.dqb_bsoftlimit = 1;
729 D.dqb_curblocks = 1;
730 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
731 break;
732
733 default:
734 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status ));
735 break;
736 }
737
738 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",
739 gqr.status,
740 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
741 gqr.getquota_rslt_u.gqr_rquota.rq_active,
742 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
743 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
744 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
745
746 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
747 *dsize = D.dqb_bsoftlimit;
748
749 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
750 *dfree = 0;
751 *dsize = D.dqb_curblocks;
752 } else
753 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
754
755 out:
756
757 if (clnt) {
758 if (clnt->cl_auth)
759 auth_destroy(clnt->cl_auth);
760 clnt_destroy(clnt);
761 }
762
763 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
764
765 SAFE_FREE(cutstr);
766 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
767 return ret;
768}
769#endif
770
771/****************************************************************************
772try to get the disk space from disk quotas (SunOS & Solaris2 version)
773Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
774****************************************************************************/
775
776bool disk_quotas(const char *path,
777 uint64_t *bsize,
778 uint64_t *dfree,
779 uint64_t *dsize)
780{
781 uid_t euser_id;
782 int ret;
783 struct dqblk D;
784#if defined(SUNOS5)
785 struct quotctl command;
786 int file;
787 struct mnttab mnt;
788#else /* SunOS4 */
789 struct mntent *mnt;
790#endif
791 char *name = NULL;
792 FILE *fd;
793 SMB_STRUCT_STAT sbuf;
794 SMB_DEV_T devno;
795 bool found = false;
796
797 euser_id = geteuid();
798
799 if (sys_stat(path, &sbuf, false) == -1) {
800 return false;
801 }
802
803 devno = sbuf.st_ex_dev ;
804 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
805 path, (unsigned int)devno));
806#if defined(SUNOS5)
807 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
808 return false;
809 }
810
811 while (getmntent(fd, &mnt) == 0) {
812 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
813 continue;
814 }
815
816 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
817 mnt.mnt_mountp, (unsigned int)devno));
818
819 /* quotas are only on vxfs, UFS or NFS */
820 if ((sbuf.st_ex_dev == devno) && (
821 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
822 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
823 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
824 found = true;
825 name = talloc_asprintf(talloc_tos(),
826 "%s/quotas",
827 mnt.mnt_mountp);
828 break;
829 }
830 }
831
832 fclose(fd);
833#else /* SunOS4 */
834 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
835 return false;
836 }
837
838 while ((mnt = getmntent(fd)) != NULL) {
839 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
840 continue;
841 }
842 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
843 mnt->mnt_dir,
844 (unsigned int)sbuf.st_ex_dev));
845 if (sbuf.st_ex_dev == devno) {
846 found = true;
847 name = talloc_strdup(talloc_tos(),
848 mnt->mnt_fsname);
849 break;
850 }
851 }
852
853 endmntent(fd);
854#endif
855 if (!found) {
856 return false;
857 }
858
859 if (!name) {
860 return false;
861 }
862 become_root();
863
864#if defined(SUNOS5)
865 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
866 bool retval;
867 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
868 mnt.mnt_special));
869 retval = nfs_quotas(mnt.mnt_special,
870 euser_id, bsize, dfree, dsize);
871 unbecome_root();
872 return retval;
873 }
874
875 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
876 if((file=sys_open(name, O_RDONLY,0))<0) {
877 unbecome_root();
878 return false;
879 }
880 command.op = Q_GETQUOTA;
881 command.uid = euser_id;
882 command.addr = (caddr_t) &D;
883 ret = ioctl(file, Q_QUOTACTL, &command);
884 close(file);
885#else
886 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
887 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
888#endif
889
890 unbecome_root();
891
892 if (ret < 0) {
893 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
894 strerror(errno) ));
895
896#if defined(SUNOS5) && defined(VXFS_QUOTA)
897 /* If normal quotactl() fails, try vxfs private calls */
898 set_effective_uid(euser_id);
899 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
900 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
901 bool retval;
902 retval = disk_quotas_vxfs(name, path,
903 bsize, dfree, dsize);
904 return retval;
905 }
906#else
907 return false;
908#endif
909 }
910
911 /* If softlimit is zero, set it equal to hardlimit.
912 */
913
914 if (D.dqb_bsoftlimit==0) {
915 D.dqb_bsoftlimit = D.dqb_bhardlimit;
916 }
917
918 /* Use softlimit to determine disk space. A user exceeding the quota
919 * is told that there's no space left. Writes might actually work for
920 * a bit if the hardlimit is set higher than softlimit. Effectively
921 * the disk becomes made of rubber latex and begins to expand to
922 * accommodate the user :-)
923 */
924
925 if (D.dqb_bsoftlimit==0)
926 return(False);
927 *bsize = DEV_BSIZE;
928 *dsize = D.dqb_bsoftlimit;
929
930 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
931 *dfree = 0;
932 *dsize = D.dqb_curblocks;
933 } else {
934 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
935 }
936
937 DEBUG(5,("disk_quotas for path \"%s\" returning "
938 "bsize %.0f, dfree %.0f, dsize %.0f\n",
939 path,(double)*bsize,(double)*dfree,(double)*dsize));
940
941 return true;
942}
943
944
945#elif defined(OSF1)
946#include <ufs/quota.h>
947
948/****************************************************************************
949try to get the disk space from disk quotas - OSF1 version
950****************************************************************************/
951
952bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
953{
954 int r, save_errno;
955 struct dqblk D;
956 SMB_STRUCT_STAT S;
957 uid_t euser_id;
958
959 /*
960 * This code presumes that OSF1 will only
961 * give out quota info when the real uid
962 * matches the effective uid. JRA.
963 */
964 euser_id = geteuid();
965 save_re_uid();
966 if (set_re_uid() != 0) return False;
967
968 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
969 if (r) {
970 save_errno = errno;
971 }
972
973 restore_re_uid();
974
975 *bsize = DEV_BSIZE;
976
977 if (r)
978 {
979 if (save_errno == EDQUOT) /* disk quota exceeded */
980 {
981 *dfree = 0;
982 *dsize = D.dqb_curblocks;
983 return (True);
984 }
985 else
986 return (False);
987 }
988
989 /* If softlimit is zero, set it equal to hardlimit.
990 */
991
992 if (D.dqb_bsoftlimit==0)
993 D.dqb_bsoftlimit = D.dqb_bhardlimit;
994
995 /* Use softlimit to determine disk space, except when it has been exceeded */
996
997 if (D.dqb_bsoftlimit==0)
998 return(False);
999
1000 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
1001 *dfree = 0;
1002 *dsize = D.dqb_curblocks;
1003 } else {
1004 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1005 *dsize = D.dqb_bsoftlimit;
1006 }
1007 return (True);
1008}
1009
1010#elif defined (IRIX6)
1011/****************************************************************************
1012try to get the disk space from disk quotas (IRIX 6.2 version)
1013****************************************************************************/
1014
1015#include <sys/quota.h>
1016#include <mntent.h>
1017
1018bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1019{
1020 uid_t euser_id;
1021 int r;
1022 struct dqblk D;
1023 struct fs_disk_quota F;
1024 SMB_STRUCT_STAT S;
1025 FILE *fp;
1026 struct mntent *mnt;
1027 SMB_DEV_T devno;
1028 int found;
1029
1030 /* find the block device file */
1031
1032 if ( sys_stat(path, &S, false) == -1 ) {
1033 return(False) ;
1034 }
1035
1036 devno = S.st_ex_dev ;
1037
1038 fp = setmntent(MOUNTED,"r");
1039 found = False ;
1040
1041 while ((mnt = getmntent(fp))) {
1042 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
1043 continue ;
1044 if (S.st_ex_dev == devno) {
1045 found = True ;
1046 break ;
1047 }
1048 }
1049 endmntent(fp) ;
1050
1051 if (!found) {
1052 return(False);
1053 }
1054
1055 euser_id=geteuid();
1056 become_root();
1057
1058 /* Use softlimit to determine disk space, except when it has been exceeded */
1059
1060 *bsize = 512;
1061
1062 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
1063 {
1064 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
1065
1066 unbecome_root();
1067
1068 if (r==-1)
1069 return(False);
1070
1071 /* Use softlimit to determine disk space, except when it has been exceeded */
1072 if (
1073 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
1074 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
1075 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
1076 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
1077 )
1078 {
1079 *dfree = 0;
1080 *dsize = D.dqb_curblocks;
1081 }
1082 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
1083 {
1084 return(False);
1085 }
1086 else
1087 {
1088 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1089 *dsize = D.dqb_bsoftlimit;
1090 }
1091
1092 }
1093 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
1094 {
1095 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
1096
1097 unbecome_root();
1098
1099 if (r==-1)
1100 {
1101 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
1102 return(False);
1103 }
1104
1105 /* No quota for this user. */
1106 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1107 {
1108 return(False);
1109 }
1110
1111 /* Use softlimit to determine disk space, except when it has been exceeded */
1112 if (
1113 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1114 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1115 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1116 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1117 )
1118 {
1119 *dfree = 0;
1120 *dsize = F.d_bcount;
1121 }
1122 else
1123 {
1124 *dfree = (F.d_blk_softlimit - F.d_bcount);
1125 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1126 }
1127
1128 }
1129 else
1130 {
1131 unbecome_root();
1132 return(False);
1133 }
1134
1135 return (True);
1136
1137}
1138
1139#else
1140
1141#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1142#include <ufs/ufs/quota.h>
1143#include <machine/param.h>
1144#elif AIX
1145/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1146#include <jfs/quota.h>
1147/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1148#define dqb_curfiles dqb_curinodes
1149#define dqb_fhardlimit dqb_ihardlimit
1150#define dqb_fsoftlimit dqb_isoftlimit
1151#ifdef _AIXVERSION_530
1152#include <sys/statfs.h>
1153#include <sys/vmount.h>
1154#endif /* AIX 5.3 */
1155#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1156#include <sys/quota.h>
1157#include <devnm.h>
1158#endif
1159
1160#if defined(__FreeBSD__) || defined(__DragonFly__)
1161
1162#include <rpc/rpc.h>
1163#include <rpc/types.h>
1164#include <rpcsvc/rquota.h>
1165#ifdef HAVE_RPC_NETTYPE_H
1166#include <rpc/nettype.h>
1167#endif
1168#include <rpc/xdr.h>
1169
1170static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1171{
1172 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1173 return(0);
1174 if (!xdr_int(xdrsp, &args->gqa_uid))
1175 return(0);
1176 return (1);
1177}
1178
1179static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1180{
1181 int quotastat;
1182
1183 if (!xdr_int(xdrsp, &quotastat)) {
1184 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1185 return 0;
1186 }
1187 gqr->status = quotastat;
1188
1189 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1190 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1191 return 0;
1192 }
1193 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1194 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1195 return 0;
1196 }
1197 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1198 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1199 return 0;
1200 }
1201 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1202 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1203 return 0;
1204 }
1205 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1206 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1207 return 0;
1208 }
1209 return (1);
1210}
1211
1212/* Works on FreeBSD, too. :-) */
1213static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1214{
1215 uid_t uid = euser_id;
1216 struct dqblk D;
1217 char *mnttype = nfspath;
1218 CLIENT *clnt;
1219 struct getquota_rslt gqr;
1220 struct getquota_args args;
1221 char *cutstr, *pathname, *host, *testpath;
1222 int len;
1223 static struct timeval timeout = {2,0};
1224 enum clnt_stat clnt_stat;
1225 bool ret = True;
1226
1227 *bsize = *dfree = *dsize = (uint64_t)0;
1228
1229 len=strcspn(mnttype, ":");
1230 pathname=strstr(mnttype, ":");
1231 cutstr = (char *) SMB_MALLOC(len+1);
1232 if (!cutstr)
1233 return False;
1234
1235 memset(cutstr, '\0', len+1);
1236 host = strncat(cutstr,mnttype, sizeof(char) * len );
1237 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1238 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1239 testpath=strchr_m(mnttype, ':');
1240 args.gqa_pathp = testpath+1;
1241 args.gqa_uid = uid;
1242
1243 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1244
1245 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1246 ret = False;
1247 goto out;
1248 }
1249
1250 clnt->cl_auth = authunix_create_default();
1251 DEBUG(9,("nfs_quotas: auth_success\n"));
1252
1253 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);
1254
1255 if (clnt_stat != RPC_SUCCESS) {
1256 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1257 ret = False;
1258 goto out;
1259 }
1260
1261 /*
1262 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1263 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1264 * something sensible.
1265 */
1266
1267 switch (gqr.status) {
1268 case 0:
1269 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1270 ret = False;
1271 goto out;
1272
1273 case 1:
1274 DEBUG(9,("nfs_quotas: Good quota data\n"));
1275 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1276 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1277 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1278 break;
1279
1280 case 2:
1281 case 3:
1282 D.dqb_bsoftlimit = 1;
1283 D.dqb_curblocks = 1;
1284 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1285 break;
1286
1287 default:
1288 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1289 break;
1290 }
1291
1292 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",
1293 gqr.status,
1294 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1295 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1296 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1297 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1298 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1299
1300 if (D.dqb_bsoftlimit == 0)
1301 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1302 if (D.dqb_bsoftlimit == 0)
1303 return False;
1304
1305 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1306 *dsize = D.dqb_bsoftlimit;
1307
1308 if (D.dqb_curblocks == 1)
1309 *bsize = DEV_BSIZE;
1310
1311 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1312 *dfree = 0;
1313 *dsize = D.dqb_curblocks;
1314 } else
1315 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1316
1317 out:
1318
1319 if (clnt) {
1320 if (clnt->cl_auth)
1321 auth_destroy(clnt->cl_auth);
1322 clnt_destroy(clnt);
1323 }
1324
1325 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1326
1327 SAFE_FREE(cutstr);
1328 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1329 return ret;
1330}
1331
1332#endif
1333
1334/****************************************************************************
1335try to get the disk space from disk quotas - default version
1336****************************************************************************/
1337
1338bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1339{
1340 int r;
1341 struct dqblk D;
1342 uid_t euser_id;
1343#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1344 char dev_disk[256];
1345 SMB_STRUCT_STAT S;
1346
1347 /* find the block device file */
1348
1349#ifdef HPUX
1350 /* Need to set the cache flag to 1 for HPUX. Seems
1351 * to have a significant performance boost when
1352 * lstat calls on /dev access this function.
1353 */
1354 if ((sys_stat(path, &S, false)<0)
1355 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1356#else
1357 if ((sys_stat(path, &S, false)<0)
1358 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1359 return (False);
1360#endif /* ifdef HPUX */
1361
1362#endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1363
1364 euser_id = geteuid();
1365
1366#ifdef HPUX
1367 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1368 save_re_uid();
1369 if (set_re_uid() != 0) return False;
1370
1371 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1372
1373 restore_re_uid();
1374#else
1375#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1376 {
1377 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1378 gid_t egrp_id;
1379#if defined(__FreeBSD__) || defined(__DragonFly__)
1380 SMB_DEV_T devno;
1381 struct statfs *mnts;
1382 SMB_STRUCT_STAT st;
1383 int mntsize, i;
1384
1385 if (sys_stat(path, &st, false) < 0)
1386 return False;
1387 devno = st.st_ex_dev;
1388
1389 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1390 if (mntsize <= 0)
1391 return False;
1392
1393 for (i = 0; i < mntsize; i++) {
1394 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1395 return False;
1396 if (st.st_ex_dev == devno)
1397 break;
1398 }
1399 if (i == mntsize)
1400 return False;
1401#endif
1402
1403 become_root();
1404
1405#if defined(__FreeBSD__) || defined(__DragonFly__)
1406 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1407 bool retval;
1408 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1409 unbecome_root();
1410 return retval;
1411 }
1412#endif
1413
1414 egrp_id = getegid();
1415 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1416
1417 /* As FreeBSD has group quotas, if getting the user
1418 quota fails, try getting the group instead. */
1419 if (r) {
1420 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1421 }
1422
1423 unbecome_root();
1424 }
1425#elif defined(AIX)
1426 /* AIX has both USER and GROUP quotas:
1427 Get the USER quota (ohnielse@fysik.dtu.dk) */
1428#ifdef _AIXVERSION_530
1429 {
1430 struct statfs statbuf;
1431 quota64_t user_quota;
1432 if (statfs(path,&statbuf) != 0)
1433 return False;
1434 if(statbuf.f_vfstype == MNT_J2)
1435 {
1436 /* For some reason we need to be root for jfs2 */
1437 become_root();
1438 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1439 unbecome_root();
1440 /* Copy results to old struct to let the following code work as before */
1441 D.dqb_curblocks = user_quota.bused;
1442 D.dqb_bsoftlimit = user_quota.bsoft;
1443 D.dqb_bhardlimit = user_quota.bhard;
1444 D.dqb_curfiles = user_quota.iused;
1445 D.dqb_fsoftlimit = user_quota.isoft;
1446 D.dqb_fhardlimit = user_quota.ihard;
1447 }
1448 else if(statbuf.f_vfstype == MNT_JFS)
1449 {
1450#endif /* AIX 5.3 */
1451 save_re_uid();
1452 if (set_re_uid() != 0)
1453 return False;
1454 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1455 restore_re_uid();
1456#ifdef _AIXVERSION_530
1457 }
1458 else
1459 r = 1; /* Fail for other FS-types */
1460 }
1461#endif /* AIX 5.3 */
1462#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1463 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1464#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1465#endif /* HPUX */
1466
1467 /* Use softlimit to determine disk space, except when it has been exceeded */
1468#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1469 *bsize = DEV_BSIZE;
1470#else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1471 *bsize = 1024;
1472#endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1473
1474 if (r)
1475 {
1476 if (errno == EDQUOT)
1477 {
1478 *dfree =0;
1479 *dsize =D.dqb_curblocks;
1480 return (True);
1481 }
1482 else return(False);
1483 }
1484
1485 /* If softlimit is zero, set it equal to hardlimit.
1486 */
1487
1488 if (D.dqb_bsoftlimit==0)
1489 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1490
1491 if (D.dqb_bsoftlimit==0)
1492 return(False);
1493 /* Use softlimit to determine disk space, except when it has been exceeded */
1494 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1495#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1496||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1497#endif
1498 ) {
1499 *dfree = 0;
1500 *dsize = D.dqb_curblocks;
1501 }
1502 else {
1503 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1504 *dsize = D.dqb_bsoftlimit;
1505 }
1506 return (True);
1507}
1508
1509#endif
1510
1511#if defined(VXFS_QUOTA)
1512
1513/****************************************************************************
1514Try to get the disk space from Veritas disk quotas.
1515 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1516
1517Background assumptions:
1518 Potentially under many Operating Systems. Initially Solaris 2.
1519
1520 My guess is that Veritas is largely, though not entirely,
1521 independent of OS. So I have separated it out.
1522
1523 There may be some details. For example, OS-specific "include" files.
1524
1525 It is understood that HPUX 10 somehow gets Veritas quotas without
1526 any special effort; if so, this routine need not be compiled in.
1527 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1528
1529Warning:
1530 It is understood that Veritas do not publicly support this ioctl interface.
1531 Rather their preference would be for the user (us) to call the native
1532 OS and then for the OS itself to call through to the VxFS filesystem.
1533 Presumably HPUX 10, see above, does this.
1534
1535Hints for porting:
1536 Add your OS to "IFLIST" below.
1537 Get it to compile successfully:
1538 Almost certainly "include"s require attention: see SUNOS5.
1539 In the main code above, arrange for it to be called: see SUNOS5.
1540 Test!
1541
1542****************************************************************************/
1543
1544/* "IFLIST"
1545 * This "if" is a list of ports:
1546 * if defined(OS1) || defined(OS2) || ...
1547 */
1548#if defined(SUNOS5)
1549
1550#if defined(SUNOS5)
1551#include <sys/fs/vx_solaris.h>
1552#endif
1553#include <sys/fs/vx_machdep.h>
1554#include <sys/fs/vx_layout.h>
1555#include <sys/fs/vx_quota.h>
1556#include <sys/fs/vx_aioctl.h>
1557#include <sys/fs/vx_ioctl.h>
1558
1559bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1560{
1561 uid_t user_id, euser_id;
1562 int ret;
1563 struct vx_dqblk D;
1564 struct vx_quotctl quotabuf;
1565 struct vx_genioctl genbuf;
1566 char *qfname;
1567 int file;
1568
1569 /*
1570 * "name" may or may not include a trailing "/quotas".
1571 * Arranging consistency of calling here in "quotas.c" may not be easy and
1572 * it might be easier to examine and adjust it here.
1573 * Fortunately, VxFS seems not to mind at present.
1574 */
1575 qfname = talloc_strdup(talloc_tos(), name);
1576 if (!qfname) {
1577 return false;
1578 }
1579 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1580
1581 euser_id = geteuid();
1582 set_effective_uid(0);
1583
1584 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1585 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1586 set_effective_uid(euser_id);
1587 return(False);
1588 }
1589 genbuf.ioc_cmd = VX_QUOTACTL;
1590 genbuf.ioc_up = (void *) &quotabuf;
1591
1592 quotabuf.cmd = VX_GETQUOTA;
1593 quotabuf.uid = euser_id;
1594 quotabuf.addr = (caddr_t) &D;
1595 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1596 close(file);
1597
1598 set_effective_uid(euser_id);
1599
1600 if (ret < 0) {
1601 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1602 return(False);
1603 }
1604
1605 /* If softlimit is zero, set it equal to hardlimit.
1606 */
1607
1608 if (D.dqb_bsoftlimit==0)
1609 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1610
1611 /* Use softlimit to determine disk space. A user exceeding the quota is told
1612 * that there's no space left. Writes might actually work for a bit if the
1613 * hardlimit is set higher than softlimit. Effectively the disk becomes
1614 * made of rubber latex and begins to expand to accommodate the user :-)
1615 */
1616 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1617 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1618 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1619
1620 if (D.dqb_bsoftlimit==0)
1621 return(False);
1622 *bsize = DEV_BSIZE;
1623 *dsize = D.dqb_bsoftlimit;
1624
1625 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1626 *dfree = 0;
1627 *dsize = D.dqb_curblocks;
1628 } else
1629 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1630
1631 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1632 path,(double)*bsize,(double)*dfree,(double)*dsize));
1633
1634 return(True);
1635}
1636
1637#endif /* SUNOS5 || ... */
1638
1639#endif /* VXFS_QUOTA */
1640
1641#else /* WITH_QUOTAS */
1642
1643bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1644{
1645 (*bsize) = 512; /* This value should be ignored */
1646
1647 /* And just to be sure we set some values that hopefully */
1648 /* will be larger that any possible real-world value */
1649 (*dfree) = (uint64_t)-1;
1650 (*dsize) = (uint64_t)-1;
1651
1652 /* As we have select not to use quotas, allways fail */
1653 return false;
1654}
1655#endif /* WITH_QUOTAS */
1656
1657#else /* HAVE_SYS_QUOTAS */
1658/* wrapper to the new sys_quota interface
1659 this file should be removed later
1660 */
1661bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1662{
1663 int r;
1664 SMB_DISK_QUOTA D;
1665 unid_t id;
1666
1667 id.uid = geteuid();
1668
1669 ZERO_STRUCT(D);
1670 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1671
1672 /* Use softlimit to determine disk space, except when it has been exceeded */
1673 *bsize = D.bsize;
1674 if (r == -1) {
1675 if (errno == EDQUOT) {
1676 *dfree =0;
1677 *dsize =D.curblocks;
1678 return (True);
1679 } else {
1680 goto try_group_quota;
1681 }
1682 }
1683
1684 /* Use softlimit to determine disk space, except when it has been exceeded */
1685 if (
1686 (D.softlimit && D.curblocks >= D.softlimit) ||
1687 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1688 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1689 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1690 ) {
1691 *dfree = 0;
1692 *dsize = D.curblocks;
1693 } else if (D.softlimit==0 && D.hardlimit==0) {
1694 goto try_group_quota;
1695 } else {
1696 if (D.softlimit == 0)
1697 D.softlimit = D.hardlimit;
1698 *dfree = D.softlimit - D.curblocks;
1699 *dsize = D.softlimit;
1700 }
1701
1702 return True;
1703
1704try_group_quota:
1705 id.gid = getegid();
1706
1707 ZERO_STRUCT(D);
1708 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1709
1710 /* Use softlimit to determine disk space, except when it has been exceeded */
1711 *bsize = D.bsize;
1712 if (r == -1) {
1713 if (errno == EDQUOT) {
1714 *dfree =0;
1715 *dsize =D.curblocks;
1716 return (True);
1717 } else {
1718 return False;
1719 }
1720 }
1721
1722 /* Use softlimit to determine disk space, except when it has been exceeded */
1723 if (
1724 (D.softlimit && D.curblocks >= D.softlimit) ||
1725 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1726 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1727 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1728 ) {
1729 *dfree = 0;
1730 *dsize = D.curblocks;
1731 } else if (D.softlimit==0 && D.hardlimit==0) {
1732 return False;
1733 } else {
1734 if (D.softlimit == 0)
1735 D.softlimit = D.hardlimit;
1736 *dfree = D.softlimit - D.curblocks;
1737 *dsize = D.softlimit;
1738 }
1739
1740 return (True);
1741}
1742#endif /* HAVE_SYS_QUOTAS */
Note: See TracBrowser for help on using the repository browser.