source: branches/samba-3.3.x/source/smbd/quotas.c@ 285

Last change on this file since 285 was 206, checked in by Herwig Bauernfeind, 16 years ago

Import Samba 3.3 branch at 3.0.0 level (psmedley's port)

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