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

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

Samba Server: updated trunk to 3.6.0

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 == 1)
750 *bsize = 512;
751
752 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
753 *dfree = 0;
754 *dsize = D.dqb_curblocks;
755 } else
756 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
757
758 out:
759
760 if (clnt) {
761 if (clnt->cl_auth)
762 auth_destroy(clnt->cl_auth);
763 clnt_destroy(clnt);
764 }
765
766 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
767
768 SAFE_FREE(cutstr);
769 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
770 return ret;
771}
772#endif
773
774/****************************************************************************
775try to get the disk space from disk quotas (SunOS & Solaris2 version)
776Quota code by Peter Urbanec (amiga@cse.unsw.edu.au).
777****************************************************************************/
778
779bool disk_quotas(const char *path,
780 uint64_t *bsize,
781 uint64_t *dfree,
782 uint64_t *dsize)
783{
784 uid_t euser_id;
785 int ret;
786 struct dqblk D;
787#if defined(SUNOS5)
788 struct quotctl command;
789 int file;
790 struct mnttab mnt;
791#else /* SunOS4 */
792 struct mntent *mnt;
793#endif
794 char *name = NULL;
795 FILE *fd;
796 SMB_STRUCT_STAT sbuf;
797 SMB_DEV_T devno;
798 bool found = false;
799
800 euser_id = geteuid();
801
802 if (sys_stat(path, &sbuf, false) == -1) {
803 return false;
804 }
805
806 devno = sbuf.st_ex_dev ;
807 DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n",
808 path, (unsigned int)devno));
809#if defined(SUNOS5)
810 if ((fd = sys_fopen(MNTTAB, "r")) == NULL) {
811 return false;
812 }
813
814 while (getmntent(fd, &mnt) == 0) {
815 if (sys_stat(mnt.mnt_mountp, &sbuf, false) == -1) {
816 continue;
817 }
818
819 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
820 mnt.mnt_mountp, (unsigned int)devno));
821
822 /* quotas are only on vxfs, UFS or NFS */
823 if ((sbuf.st_ex_dev == devno) && (
824 strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
825 strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
826 strcmp( mnt.mnt_fstype, "vxfs" ) == 0 )) {
827 found = true;
828 name = talloc_asprintf(talloc_tos(),
829 "%s/quotas",
830 mnt.mnt_mountp);
831 break;
832 }
833 }
834
835 fclose(fd);
836#else /* SunOS4 */
837 if ((fd = setmntent(MOUNTED, "r")) == NULL) {
838 return false;
839 }
840
841 while ((mnt = getmntent(fd)) != NULL) {
842 if (sys_stat(mnt->mnt_dir, &sbuf, false) == -1) {
843 continue;
844 }
845 DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n",
846 mnt->mnt_dir,
847 (unsigned int)sbuf.st_ex_dev));
848 if (sbuf.st_ex_dev == devno) {
849 found = true;
850 name = talloc_strdup(talloc_tos(),
851 mnt->mnt_fsname);
852 break;
853 }
854 }
855
856 endmntent(fd);
857#endif
858 if (!found) {
859 return false;
860 }
861
862 if (!name) {
863 return false;
864 }
865 become_root();
866
867#if defined(SUNOS5)
868 if (strcmp(mnt.mnt_fstype, "nfs") == 0) {
869 bool retval;
870 DEBUG(5,("disk_quotas: looking for mountpath (NFS) \"%s\"\n",
871 mnt.mnt_special));
872 retval = nfs_quotas(mnt.mnt_special,
873 euser_id, bsize, dfree, dsize);
874 unbecome_root();
875 return retval;
876 }
877
878 DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name));
879 if((file=sys_open(name, O_RDONLY,0))<0) {
880 unbecome_root();
881 return false;
882 }
883 command.op = Q_GETQUOTA;
884 command.uid = euser_id;
885 command.addr = (caddr_t) &D;
886 ret = ioctl(file, Q_QUOTACTL, &command);
887 close(file);
888#else
889 DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
890 ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
891#endif
892
893 unbecome_root();
894
895 if (ret < 0) {
896 DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n",
897 strerror(errno) ));
898
899#if defined(SUNOS5) && defined(VXFS_QUOTA)
900 /* If normal quotactl() fails, try vxfs private calls */
901 set_effective_uid(euser_id);
902 DEBUG(5,("disk_quotas: mount type \"%s\"\n", mnt.mnt_fstype));
903 if ( 0 == strcmp ( mnt.mnt_fstype, "vxfs" )) {
904 bool retval;
905 retval = disk_quotas_vxfs(name, path,
906 bsize, dfree, dsize);
907 return retval;
908 }
909#else
910 return false;
911#endif
912 }
913
914 /* If softlimit is zero, set it equal to hardlimit.
915 */
916
917 if (D.dqb_bsoftlimit==0) {
918 D.dqb_bsoftlimit = D.dqb_bhardlimit;
919 }
920
921 /* Use softlimit to determine disk space. A user exceeding the quota
922 * is told that there's no space left. Writes might actually work for
923 * a bit if the hardlimit is set higher than softlimit. Effectively
924 * the disk becomes made of rubber latex and begins to expand to
925 * accommodate the user :-)
926 */
927
928 if (D.dqb_bsoftlimit==0)
929 return(False);
930 *bsize = DEV_BSIZE;
931 *dsize = D.dqb_bsoftlimit;
932
933 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
934 *dfree = 0;
935 *dsize = D.dqb_curblocks;
936 } else {
937 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
938 }
939
940 DEBUG(5,("disk_quotas for path \"%s\" returning "
941 "bsize %.0f, dfree %.0f, dsize %.0f\n",
942 path,(double)*bsize,(double)*dfree,(double)*dsize));
943
944 return true;
945}
946
947
948#elif defined(OSF1)
949#include <ufs/quota.h>
950
951/****************************************************************************
952try to get the disk space from disk quotas - OSF1 version
953****************************************************************************/
954
955bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
956{
957 int r, save_errno;
958 struct dqblk D;
959 SMB_STRUCT_STAT S;
960 uid_t euser_id;
961
962 /*
963 * This code presumes that OSF1 will only
964 * give out quota info when the real uid
965 * matches the effective uid. JRA.
966 */
967 euser_id = geteuid();
968 save_re_uid();
969 if (set_re_uid() != 0) return False;
970
971 r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
972 if (r) {
973 save_errno = errno;
974 }
975
976 restore_re_uid();
977
978 *bsize = DEV_BSIZE;
979
980 if (r)
981 {
982 if (save_errno == EDQUOT) /* disk quota exceeded */
983 {
984 *dfree = 0;
985 *dsize = D.dqb_curblocks;
986 return (True);
987 }
988 else
989 return (False);
990 }
991
992 /* If softlimit is zero, set it equal to hardlimit.
993 */
994
995 if (D.dqb_bsoftlimit==0)
996 D.dqb_bsoftlimit = D.dqb_bhardlimit;
997
998 /* Use softlimit to determine disk space, except when it has been exceeded */
999
1000 if (D.dqb_bsoftlimit==0)
1001 return(False);
1002
1003 if ((D.dqb_curblocks>D.dqb_bsoftlimit)) {
1004 *dfree = 0;
1005 *dsize = D.dqb_curblocks;
1006 } else {
1007 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1008 *dsize = D.dqb_bsoftlimit;
1009 }
1010 return (True);
1011}
1012
1013#elif defined (IRIX6)
1014/****************************************************************************
1015try to get the disk space from disk quotas (IRIX 6.2 version)
1016****************************************************************************/
1017
1018#include <sys/quota.h>
1019#include <mntent.h>
1020
1021bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1022{
1023 uid_t euser_id;
1024 int r;
1025 struct dqblk D;
1026 struct fs_disk_quota F;
1027 SMB_STRUCT_STAT S;
1028 FILE *fp;
1029 struct mntent *mnt;
1030 SMB_DEV_T devno;
1031 int found;
1032
1033 /* find the block device file */
1034
1035 if ( sys_stat(path, &S, false) == -1 ) {
1036 return(False) ;
1037 }
1038
1039 devno = S.st_ex_dev ;
1040
1041 fp = setmntent(MOUNTED,"r");
1042 found = False ;
1043
1044 while ((mnt = getmntent(fp))) {
1045 if ( sys_stat(mnt->mnt_dir, &S, false) == -1 )
1046 continue ;
1047 if (S.st_ex_dev == devno) {
1048 found = True ;
1049 break ;
1050 }
1051 }
1052 endmntent(fp) ;
1053
1054 if (!found) {
1055 return(False);
1056 }
1057
1058 euser_id=geteuid();
1059 become_root();
1060
1061 /* Use softlimit to determine disk space, except when it has been exceeded */
1062
1063 *bsize = 512;
1064
1065 if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
1066 {
1067 r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
1068
1069 unbecome_root();
1070
1071 if (r==-1)
1072 return(False);
1073
1074 /* Use softlimit to determine disk space, except when it has been exceeded */
1075 if (
1076 (D.dqb_bsoftlimit && D.dqb_curblocks>=D.dqb_bsoftlimit) ||
1077 (D.dqb_bhardlimit && D.dqb_curblocks>=D.dqb_bhardlimit) ||
1078 (D.dqb_fsoftlimit && D.dqb_curfiles>=D.dqb_fsoftlimit) ||
1079 (D.dqb_fhardlimit && D.dqb_curfiles>=D.dqb_fhardlimit)
1080 )
1081 {
1082 *dfree = 0;
1083 *dsize = D.dqb_curblocks;
1084 }
1085 else if (D.dqb_bsoftlimit==0 && D.dqb_bhardlimit==0)
1086 {
1087 return(False);
1088 }
1089 else
1090 {
1091 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1092 *dsize = D.dqb_bsoftlimit;
1093 }
1094
1095 }
1096 else if ( 0 == strcmp ( mnt->mnt_type, "xfs" ))
1097 {
1098 r=quotactl (Q_XGETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &F);
1099
1100 unbecome_root();
1101
1102 if (r==-1)
1103 {
1104 DEBUG(5, ("quotactl for uid=%u: %s", euser_id, strerror(errno)));
1105 return(False);
1106 }
1107
1108 /* No quota for this user. */
1109 if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
1110 {
1111 return(False);
1112 }
1113
1114 /* Use softlimit to determine disk space, except when it has been exceeded */
1115 if (
1116 (F.d_blk_softlimit && F.d_bcount>=F.d_blk_softlimit) ||
1117 (F.d_blk_hardlimit && F.d_bcount>=F.d_blk_hardlimit) ||
1118 (F.d_ino_softlimit && F.d_icount>=F.d_ino_softlimit) ||
1119 (F.d_ino_hardlimit && F.d_icount>=F.d_ino_hardlimit)
1120 )
1121 {
1122 *dfree = 0;
1123 *dsize = F.d_bcount;
1124 }
1125 else
1126 {
1127 *dfree = (F.d_blk_softlimit - F.d_bcount);
1128 *dsize = F.d_blk_softlimit ? F.d_blk_softlimit : F.d_blk_hardlimit;
1129 }
1130
1131 }
1132 else
1133 {
1134 unbecome_root();
1135 return(False);
1136 }
1137
1138 return (True);
1139
1140}
1141
1142#else
1143
1144#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1145#include <ufs/ufs/quota.h>
1146#include <machine/param.h>
1147#elif AIX
1148/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
1149#include <jfs/quota.h>
1150/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
1151#define dqb_curfiles dqb_curinodes
1152#define dqb_fhardlimit dqb_ihardlimit
1153#define dqb_fsoftlimit dqb_isoftlimit
1154#ifdef _AIXVERSION_530
1155#include <sys/statfs.h>
1156#include <sys/vmount.h>
1157#endif /* AIX 5.3 */
1158#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1159#include <sys/quota.h>
1160#include <devnm.h>
1161#endif
1162
1163#if defined(__FreeBSD__) || defined(__DragonFly__)
1164
1165#include <rpc/rpc.h>
1166#include <rpc/types.h>
1167#include <rpcsvc/rquota.h>
1168#ifdef HAVE_RPC_NETTYPE_H
1169#include <rpc/nettype.h>
1170#endif
1171#include <rpc/xdr.h>
1172
1173static int my_xdr_getquota_args(XDR *xdrsp, struct getquota_args *args)
1174{
1175 if (!xdr_string(xdrsp, &args->gqa_pathp, RQ_PATHLEN ))
1176 return(0);
1177 if (!xdr_int(xdrsp, &args->gqa_uid))
1178 return(0);
1179 return (1);
1180}
1181
1182static int my_xdr_getquota_rslt(XDR *xdrsp, struct getquota_rslt *gqr)
1183{
1184 int quotastat;
1185
1186 if (!xdr_int(xdrsp, &quotastat)) {
1187 DEBUG(6,("nfs_quotas: Status bad or zero\n"));
1188 return 0;
1189 }
1190 gqr->status = quotastat;
1191
1192 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsize)) {
1193 DEBUG(6,("nfs_quotas: Block size bad or zero\n"));
1194 return 0;
1195 }
1196 if (!xdr_bool(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_active)) {
1197 DEBUG(6,("nfs_quotas: Active bad or zero\n"));
1198 return 0;
1199 }
1200 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bhardlimit)) {
1201 DEBUG(6,("nfs_quotas: Hardlimit bad or zero\n"));
1202 return 0;
1203 }
1204 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_bsoftlimit)) {
1205 DEBUG(6,("nfs_quotas: Softlimit bad or zero\n"));
1206 return 0;
1207 }
1208 if (!xdr_int(xdrsp, &gqr->getquota_rslt_u.gqr_rquota.rq_curblocks)) {
1209 DEBUG(6,("nfs_quotas: Currentblocks bad or zero\n"));
1210 return 0;
1211 }
1212 return (1);
1213}
1214
1215/* Works on FreeBSD, too. :-) */
1216static bool nfs_quotas(char *nfspath, uid_t euser_id, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1217{
1218 uid_t uid = euser_id;
1219 struct dqblk D;
1220 char *mnttype = nfspath;
1221 CLIENT *clnt;
1222 struct getquota_rslt gqr;
1223 struct getquota_args args;
1224 char *cutstr, *pathname, *host, *testpath;
1225 int len;
1226 static struct timeval timeout = {2,0};
1227 enum clnt_stat clnt_stat;
1228 bool ret = True;
1229
1230 *bsize = *dfree = *dsize = (uint64_t)0;
1231
1232 len=strcspn(mnttype, ":");
1233 pathname=strstr(mnttype, ":");
1234 cutstr = (char *) SMB_MALLOC(len+1);
1235 if (!cutstr)
1236 return False;
1237
1238 memset(cutstr, '\0', len+1);
1239 host = strncat(cutstr,mnttype, sizeof(char) * len );
1240 DEBUG(5,("nfs_quotas: looking for mount on \"%s\"\n", cutstr));
1241 DEBUG(5,("nfs_quotas: of path \"%s\"\n", mnttype));
1242 testpath=strchr_m(mnttype, ':');
1243 args.gqa_pathp = testpath+1;
1244 args.gqa_uid = uid;
1245
1246 DEBUG(5,("nfs_quotas: Asking for host \"%s\" rpcprog \"%i\" rpcvers \"%i\" network \"%s\"\n", host, RQUOTAPROG, RQUOTAVERS, "udp"));
1247
1248 if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp")) == NULL) {
1249 ret = False;
1250 goto out;
1251 }
1252
1253 clnt->cl_auth = authunix_create_default();
1254 DEBUG(9,("nfs_quotas: auth_success\n"));
1255
1256 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);
1257
1258 if (clnt_stat != RPC_SUCCESS) {
1259 DEBUG(9,("nfs_quotas: clnt_call fail\n"));
1260 ret = False;
1261 goto out;
1262 }
1263
1264 /*
1265 * gqr->status returns 0 if the rpc call fails, 1 if quotas exist, 2 if there is
1266 * no quota set, and 3 if no permission to get the quota. If 0 or 3 return
1267 * something sensible.
1268 */
1269
1270 switch (gqr.status) {
1271 case 0:
1272 DEBUG(9,("nfs_quotas: Remote Quotas Failed! Error \"%i\" \n", gqr.status));
1273 ret = False;
1274 goto out;
1275
1276 case 1:
1277 DEBUG(9,("nfs_quotas: Good quota data\n"));
1278 D.dqb_bsoftlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit;
1279 D.dqb_bhardlimit = gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit;
1280 D.dqb_curblocks = gqr.getquota_rslt_u.gqr_rquota.rq_curblocks;
1281 break;
1282
1283 case 2:
1284 case 3:
1285 D.dqb_bsoftlimit = 1;
1286 D.dqb_curblocks = 1;
1287 DEBUG(9,("nfs_quotas: Remote Quotas returned \"%i\" \n", gqr.status));
1288 break;
1289
1290 default:
1291 DEBUG(9,("nfs_quotas: Remote Quotas Questionable! Error \"%i\" \n", gqr.status));
1292 break;
1293 }
1294
1295 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",
1296 gqr.status,
1297 gqr.getquota_rslt_u.gqr_rquota.rq_bsize,
1298 gqr.getquota_rslt_u.gqr_rquota.rq_active,
1299 gqr.getquota_rslt_u.gqr_rquota.rq_bhardlimit,
1300 gqr.getquota_rslt_u.gqr_rquota.rq_bsoftlimit,
1301 gqr.getquota_rslt_u.gqr_rquota.rq_curblocks));
1302
1303 if (D.dqb_bsoftlimit == 0)
1304 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1305 if (D.dqb_bsoftlimit == 0)
1306 return False;
1307
1308 *bsize = gqr.getquota_rslt_u.gqr_rquota.rq_bsize;
1309 *dsize = D.dqb_bsoftlimit;
1310
1311 if (D.dqb_curblocks == 1)
1312 *bsize = DEV_BSIZE;
1313
1314 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1315 *dfree = 0;
1316 *dsize = D.dqb_curblocks;
1317 } else
1318 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1319
1320 out:
1321
1322 if (clnt) {
1323 if (clnt->cl_auth)
1324 auth_destroy(clnt->cl_auth);
1325 clnt_destroy(clnt);
1326 }
1327
1328 DEBUG(5,("nfs_quotas: For path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",args.gqa_pathp,(double)*bsize,(double)*dfree,(double)*dsize));
1329
1330 SAFE_FREE(cutstr);
1331 DEBUG(10,("nfs_quotas: End of nfs_quotas\n" ));
1332 return ret;
1333}
1334
1335#endif
1336
1337/****************************************************************************
1338try to get the disk space from disk quotas - default version
1339****************************************************************************/
1340
1341bool disk_quotas(const char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1342{
1343 int r;
1344 struct dqblk D;
1345 uid_t euser_id;
1346#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1347 char dev_disk[256];
1348 SMB_STRUCT_STAT S;
1349
1350 /* find the block device file */
1351
1352#ifdef HPUX
1353 /* Need to set the cache flag to 1 for HPUX. Seems
1354 * to have a significant performance boost when
1355 * lstat calls on /dev access this function.
1356 */
1357 if ((sys_stat(path, &S, false)<0)
1358 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 1)<0))
1359#else
1360 if ((sys_stat(path, &S, false)<0)
1361 || (devnm(S_IFBLK, S.st_ex_dev, dev_disk, 256, 0)<0))
1362 return (False);
1363#endif /* ifdef HPUX */
1364
1365#endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1366
1367 euser_id = geteuid();
1368
1369#ifdef HPUX
1370 /* for HPUX, real uid must be same as euid to execute quotactl for euid */
1371 save_re_uid();
1372 if (set_re_uid() != 0) return False;
1373
1374 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1375
1376 restore_re_uid();
1377#else
1378#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1379 {
1380 /* FreeBSD patches from Marty Moll <martym@arbor.edu> */
1381 gid_t egrp_id;
1382#if defined(__FreeBSD__) || defined(__DragonFly__)
1383 SMB_DEV_T devno;
1384 struct statfs *mnts;
1385 SMB_STRUCT_STAT st;
1386 int mntsize, i;
1387
1388 if (sys_stat(path, &st, false) < 0)
1389 return False;
1390 devno = st.st_ex_dev;
1391
1392 mntsize = getmntinfo(&mnts,MNT_NOWAIT);
1393 if (mntsize <= 0)
1394 return False;
1395
1396 for (i = 0; i < mntsize; i++) {
1397 if (sys_stat(mnts[i].f_mntonname, &st, false) < 0)
1398 return False;
1399 if (st.st_ex_dev == devno)
1400 break;
1401 }
1402 if (i == mntsize)
1403 return False;
1404#endif
1405
1406 become_root();
1407
1408#if defined(__FreeBSD__) || defined(__DragonFly__)
1409 if (strcmp(mnts[i].f_fstypename,"nfs") == 0) {
1410 bool retval;
1411 retval = nfs_quotas(mnts[i].f_mntfromname,euser_id,bsize,dfree,dsize);
1412 unbecome_root();
1413 return retval;
1414 }
1415#endif
1416
1417 egrp_id = getegid();
1418 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1419
1420 /* As FreeBSD has group quotas, if getting the user
1421 quota fails, try getting the group instead. */
1422 if (r) {
1423 r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
1424 }
1425
1426 unbecome_root();
1427 }
1428#elif defined(AIX)
1429 /* AIX has both USER and GROUP quotas:
1430 Get the USER quota (ohnielse@fysik.dtu.dk) */
1431#ifdef _AIXVERSION_530
1432 {
1433 struct statfs statbuf;
1434 quota64_t user_quota;
1435 if (statfs(path,&statbuf) != 0)
1436 return False;
1437 if(statbuf.f_vfstype == MNT_J2)
1438 {
1439 /* For some reason we need to be root for jfs2 */
1440 become_root();
1441 r = quotactl(path,QCMD(Q_J2GETQUOTA,USRQUOTA),euser_id,(char *) &user_quota);
1442 unbecome_root();
1443 /* Copy results to old struct to let the following code work as before */
1444 D.dqb_curblocks = user_quota.bused;
1445 D.dqb_bsoftlimit = user_quota.bsoft;
1446 D.dqb_bhardlimit = user_quota.bhard;
1447 D.dqb_curfiles = user_quota.iused;
1448 D.dqb_fsoftlimit = user_quota.isoft;
1449 D.dqb_fhardlimit = user_quota.ihard;
1450 }
1451 else if(statbuf.f_vfstype == MNT_JFS)
1452 {
1453#endif /* AIX 5.3 */
1454 save_re_uid();
1455 if (set_re_uid() != 0)
1456 return False;
1457 r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
1458 restore_re_uid();
1459#ifdef _AIXVERSION_530
1460 }
1461 else
1462 r = 1; /* Fail for other FS-types */
1463 }
1464#endif /* AIX 5.3 */
1465#else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1466 r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
1467#endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1468#endif /* HPUX */
1469
1470 /* Use softlimit to determine disk space, except when it has been exceeded */
1471#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1472 *bsize = DEV_BSIZE;
1473#else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1474 *bsize = 1024;
1475#endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1476
1477 if (r)
1478 {
1479 if (errno == EDQUOT)
1480 {
1481 *dfree =0;
1482 *dsize =D.dqb_curblocks;
1483 return (True);
1484 }
1485 else return(False);
1486 }
1487
1488 /* If softlimit is zero, set it equal to hardlimit.
1489 */
1490
1491 if (D.dqb_bsoftlimit==0)
1492 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1493
1494 if (D.dqb_bsoftlimit==0)
1495 return(False);
1496 /* Use softlimit to determine disk space, except when it has been exceeded */
1497 if ((D.dqb_curblocks>D.dqb_bsoftlimit)
1498#if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1499||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
1500#endif
1501 ) {
1502 *dfree = 0;
1503 *dsize = D.dqb_curblocks;
1504 }
1505 else {
1506 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1507 *dsize = D.dqb_bsoftlimit;
1508 }
1509 return (True);
1510}
1511
1512#endif
1513
1514#if defined(VXFS_QUOTA)
1515
1516/****************************************************************************
1517Try to get the disk space from Veritas disk quotas.
1518 David Lee <T.D.Lee@durham.ac.uk> August 1999.
1519
1520Background assumptions:
1521 Potentially under many Operating Systems. Initially Solaris 2.
1522
1523 My guess is that Veritas is largely, though not entirely,
1524 independent of OS. So I have separated it out.
1525
1526 There may be some details. For example, OS-specific "include" files.
1527
1528 It is understood that HPUX 10 somehow gets Veritas quotas without
1529 any special effort; if so, this routine need not be compiled in.
1530 Dirk De Wachter <Dirk.DeWachter@rug.ac.be>
1531
1532Warning:
1533 It is understood that Veritas do not publicly support this ioctl interface.
1534 Rather their preference would be for the user (us) to call the native
1535 OS and then for the OS itself to call through to the VxFS filesystem.
1536 Presumably HPUX 10, see above, does this.
1537
1538Hints for porting:
1539 Add your OS to "IFLIST" below.
1540 Get it to compile successfully:
1541 Almost certainly "include"s require attention: see SUNOS5.
1542 In the main code above, arrange for it to be called: see SUNOS5.
1543 Test!
1544
1545****************************************************************************/
1546
1547/* "IFLIST"
1548 * This "if" is a list of ports:
1549 * if defined(OS1) || defined(OS2) || ...
1550 */
1551#if defined(SUNOS5)
1552
1553#if defined(SUNOS5)
1554#include <sys/fs/vx_solaris.h>
1555#endif
1556#include <sys/fs/vx_machdep.h>
1557#include <sys/fs/vx_layout.h>
1558#include <sys/fs/vx_quota.h>
1559#include <sys/fs/vx_aioctl.h>
1560#include <sys/fs/vx_ioctl.h>
1561
1562bool disk_quotas_vxfs(const char *name, char *path, uint64_t *bsize, uint64_t *dfree, uint64_t *dsize)
1563{
1564 uid_t user_id, euser_id;
1565 int ret;
1566 struct vx_dqblk D;
1567 struct vx_quotctl quotabuf;
1568 struct vx_genioctl genbuf;
1569 char *qfname;
1570 int file;
1571
1572 /*
1573 * "name" may or may not include a trailing "/quotas".
1574 * Arranging consistency of calling here in "quotas.c" may not be easy and
1575 * it might be easier to examine and adjust it here.
1576 * Fortunately, VxFS seems not to mind at present.
1577 */
1578 qfname = talloc_strdup(talloc_tos(), name);
1579 if (!qfname) {
1580 return false;
1581 }
1582 /* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
1583
1584 euser_id = geteuid();
1585 set_effective_uid(0);
1586
1587 DEBUG(5,("disk_quotas: looking for VxFS quotas file \"%s\"\n", qfname));
1588 if((file=sys_open(qfname, O_RDONLY,0))<0) {
1589 set_effective_uid(euser_id);
1590 return(False);
1591 }
1592 genbuf.ioc_cmd = VX_QUOTACTL;
1593 genbuf.ioc_up = (void *) &quotabuf;
1594
1595 quotabuf.cmd = VX_GETQUOTA;
1596 quotabuf.uid = euser_id;
1597 quotabuf.addr = (caddr_t) &D;
1598 ret = ioctl(file, VX_ADMIN_IOCTL, &genbuf);
1599 close(file);
1600
1601 set_effective_uid(euser_id);
1602
1603 if (ret < 0) {
1604 DEBUG(5,("disk_quotas ioctl (VxFS) failed. Error = %s\n", strerror(errno) ));
1605 return(False);
1606 }
1607
1608 /* If softlimit is zero, set it equal to hardlimit.
1609 */
1610
1611 if (D.dqb_bsoftlimit==0)
1612 D.dqb_bsoftlimit = D.dqb_bhardlimit;
1613
1614 /* Use softlimit to determine disk space. A user exceeding the quota is told
1615 * that there's no space left. Writes might actually work for a bit if the
1616 * hardlimit is set higher than softlimit. Effectively the disk becomes
1617 * made of rubber latex and begins to expand to accommodate the user :-)
1618 */
1619 DEBUG(5,("disk_quotas for path \"%s\" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld\n",
1620 path, D.dqb_curblocks, D.dqb_bsoftlimit, D.dqb_bhardlimit,
1621 D.dqb_curfiles, D.dqb_fsoftlimit, D.dqb_fhardlimit));
1622
1623 if (D.dqb_bsoftlimit==0)
1624 return(False);
1625 *bsize = DEV_BSIZE;
1626 *dsize = D.dqb_bsoftlimit;
1627
1628 if (D.dqb_curblocks > D.dqb_bsoftlimit) {
1629 *dfree = 0;
1630 *dsize = D.dqb_curblocks;
1631 } else
1632 *dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
1633
1634 DEBUG(5,("disk_quotas for path \"%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n",
1635 path,(double)*bsize,(double)*dfree,(double)*dsize));
1636
1637 return(True);
1638}
1639
1640#endif /* SUNOS5 || ... */
1641
1642#endif /* VXFS_QUOTA */
1643
1644#else /* WITH_QUOTAS */
1645
1646bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1647{
1648 (*bsize) = 512; /* This value should be ignored */
1649
1650 /* And just to be sure we set some values that hopefully */
1651 /* will be larger that any possible real-world value */
1652 (*dfree) = (uint64_t)-1;
1653 (*dsize) = (uint64_t)-1;
1654
1655 /* As we have select not to use quotas, allways fail */
1656 return false;
1657}
1658#endif /* WITH_QUOTAS */
1659
1660#else /* HAVE_SYS_QUOTAS */
1661/* wrapper to the new sys_quota interface
1662 this file should be removed later
1663 */
1664bool disk_quotas(const char *path,uint64_t *bsize,uint64_t *dfree,uint64_t *dsize)
1665{
1666 int r;
1667 SMB_DISK_QUOTA D;
1668 unid_t id;
1669
1670 id.uid = geteuid();
1671
1672 ZERO_STRUCT(D);
1673 r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
1674
1675 /* Use softlimit to determine disk space, except when it has been exceeded */
1676 *bsize = D.bsize;
1677 if (r == -1) {
1678 if (errno == EDQUOT) {
1679 *dfree =0;
1680 *dsize =D.curblocks;
1681 return (True);
1682 } else {
1683 goto try_group_quota;
1684 }
1685 }
1686
1687 /* Use softlimit to determine disk space, except when it has been exceeded */
1688 if (
1689 (D.softlimit && D.curblocks >= D.softlimit) ||
1690 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1691 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1692 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1693 ) {
1694 *dfree = 0;
1695 *dsize = D.curblocks;
1696 } else if (D.softlimit==0 && D.hardlimit==0) {
1697 goto try_group_quota;
1698 } else {
1699 if (D.softlimit == 0)
1700 D.softlimit = D.hardlimit;
1701 *dfree = D.softlimit - D.curblocks;
1702 *dsize = D.softlimit;
1703 }
1704
1705 return True;
1706
1707try_group_quota:
1708 id.gid = getegid();
1709
1710 ZERO_STRUCT(D);
1711 r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
1712
1713 /* Use softlimit to determine disk space, except when it has been exceeded */
1714 *bsize = D.bsize;
1715 if (r == -1) {
1716 if (errno == EDQUOT) {
1717 *dfree =0;
1718 *dsize =D.curblocks;
1719 return (True);
1720 } else {
1721 return False;
1722 }
1723 }
1724
1725 /* Use softlimit to determine disk space, except when it has been exceeded */
1726 if (
1727 (D.softlimit && D.curblocks >= D.softlimit) ||
1728 (D.hardlimit && D.curblocks >= D.hardlimit) ||
1729 (D.isoftlimit && D.curinodes >= D.isoftlimit) ||
1730 (D.ihardlimit && D.curinodes>=D.ihardlimit)
1731 ) {
1732 *dfree = 0;
1733 *dsize = D.curblocks;
1734 } else if (D.softlimit==0 && D.hardlimit==0) {
1735 return False;
1736 } else {
1737 if (D.softlimit == 0)
1738 D.softlimit = D.hardlimit;
1739 *dfree = D.softlimit - D.curblocks;
1740 *dsize = D.softlimit;
1741 }
1742
1743 return (True);
1744}
1745#endif /* HAVE_SYS_QUOTAS */
Note: See TracBrowser for help on using the repository browser.