source: trunk/samba-3.0.25pre1/source/smbd/quotas.c@ 1

Last change on this file since 1 was 1, checked in by Paul Smedley, 18 years ago

Initial code import

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