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