1/*
2   Unix SMB/CIFS implementation.
3   System QUOTA function wrappers for XFS
4   Copyright (C) Stefan (metze) Metzmacher	2003
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#include "includes.h"
23
24#undef DBGC_CLASS
25#define DBGC_CLASS DBGC_QUOTA
26
27#ifndef HAVE_SYS_QUOTAS
28#ifdef HAVE_XFS_QUOTAS
29#undef HAVE_XFS_QUOTAS
30#endif
31#endif
32
33#ifdef HAVE_XFS_QUOTAS
34
35#ifdef HAVE_LINUX_XFS_QUOTAS
36#include "samba_linux_quota.h"
37#include "samba_xfs_quota.h"
38#define HAVE_GROUP_QUOTA
39#else /* IRIX */
40#include <sys/quota.h>
41#endif
42
43/* on IRIX */
44#ifndef Q_XQUOTAON
45#define Q_XQUOTAON Q_QUOTAON
46#endif /* Q_XQUOTAON */
47#ifndef Q_XQUOTAOFF
48#define Q_XQUOTAOFF Q_QUOTAOFF
49#endif /* Q_XQUOTAOFF */
50#ifndef Q_XGETQSTAT
51#define Q_XGETQSTAT Q_GETQSTAT
52#endif /* Q_XGETQSTAT */
53
54/* currently doesn't support Group and Project quotas on IRIX
55 */
56
57#ifndef QCMD
58#define QCMD(x,y) x
59#endif
60
61/*
62 * IRIX has BBSIZE in <sys/param.h>
63 */
64#ifndef BBSHIFT
65#define	BBSHIFT		9
66#endif /* BBSHIFT */
67#ifndef BBSIZE
68#define	BBSIZE		(1<<BBSHIFT)
69#endif /* BBSIZE */
70
71/****************************************************************************
72 Abstract out the XFS Quota Manager quota get call.
73****************************************************************************/
74int sys_get_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
75{
76	int ret = -1;
77	uint32 qflags = 0;
78	SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
79	struct fs_disk_quota D;
80	struct fs_quota_stat F;
81	ZERO_STRUCT(D);
82	ZERO_STRUCT(F);
83
84	if (!bdev||!dp)
85		smb_panic("sys_get_xfs_quota: called with NULL pointer");
86
87	ZERO_STRUCT(*dp);
88	dp->qtype = qtype;
89
90	switch (qtype) {
91		case SMB_USER_QUOTA_TYPE:
92			DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
93				path, bdev, (unsigned)id.uid));
94
95			if ((ret=quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D)))
96				return ret;
97			break;
98#ifdef HAVE_GROUP_QUOTA
99		case SMB_GROUP_QUOTA_TYPE:
100			DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
101				path, bdev, (unsigned)id.gid));
102
103			if ((ret=quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D)))
104				return ret;
105			break;
106#endif /* HAVE_GROUP_QUOTA */
107		case SMB_USER_FS_QUOTA_TYPE:
108			DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
109				path, bdev, (unsigned)id.uid));
110
111			quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
112
113			if (F.qs_flags & XFS_QUOTA_UDQ_ENFD) {
114				qflags |= QUOTAS_DENY_DISK;
115			}
116			else if (F.qs_flags & XFS_QUOTA_UDQ_ACCT) {
117				qflags |= QUOTAS_ENABLED;
118			}
119
120			ret = 0;
121
122			break;
123#ifdef HAVE_GROUP_QUOTA
124		case SMB_GROUP_FS_QUOTA_TYPE:
125			DEBUG(10,("sys_get_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
126				path, bdev, (unsigned)id.gid));
127
128			quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
129
130			if (F.qs_flags & XFS_QUOTA_GDQ_ENFD) {
131				qflags |= QUOTAS_DENY_DISK;
132			}
133			else if (F.qs_flags & XFS_QUOTA_GDQ_ACCT) {
134				qflags |= QUOTAS_ENABLED;
135			}
136
137			ret = 0;
138
139			break;
140#endif /* HAVE_GROUP_QUOTA */
141		default:
142			errno = ENOSYS;
143			return -1;
144	}
145
146	dp->bsize = bsize;
147	dp->softlimit = (SMB_BIG_UINT)D.d_blk_softlimit;
148	dp->hardlimit = (SMB_BIG_UINT)D.d_blk_hardlimit;
149	dp->ihardlimit = (SMB_BIG_UINT)D.d_ino_hardlimit;
150	dp->isoftlimit = (SMB_BIG_UINT)D.d_ino_softlimit;
151	dp->curinodes = (SMB_BIG_UINT)D.d_icount;
152	dp->curblocks = (SMB_BIG_UINT)D.d_bcount;
153	dp->qflags = qflags;
154
155	return ret;
156}
157
158/****************************************************************************
159 Abstract out the XFS Quota Manager quota set call.
160****************************************************************************/
161int sys_set_xfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
162{
163	int ret = -1;
164	uint32 qflags = 0;
165	SMB_BIG_UINT bsize = (SMB_BIG_UINT)BBSIZE;
166	struct fs_disk_quota D;
167	struct fs_quota_stat F;
168	int q_on = 0;
169	int q_off = 0;
170	ZERO_STRUCT(D);
171	ZERO_STRUCT(F);
172
173	if (!bdev||!dp)
174		smb_panic("sys_set_xfs_quota: called with NULL pointer");
175
176	if (bsize == dp->bsize) {
177		D.d_blk_softlimit = dp->softlimit;
178		D.d_blk_hardlimit = dp->hardlimit;
179		D.d_ino_hardlimit = dp->ihardlimit;
180		D.d_ino_softlimit = dp->isoftlimit;
181	} else {
182		D.d_blk_softlimit = (dp->softlimit*dp->bsize)/bsize;
183		D.d_blk_hardlimit = (dp->hardlimit*dp->bsize)/bsize;
184		D.d_ino_hardlimit = (dp->ihardlimit*dp->bsize)/bsize;
185		D.d_ino_softlimit = (dp->isoftlimit*dp->bsize)/bsize;
186	}
187
188	qflags = dp->qflags;
189
190	switch (qtype) {
191		case SMB_USER_QUOTA_TYPE:
192			DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
193				path, bdev, (unsigned)id.uid));
194
195			D.d_fieldmask |= FS_DQ_LIMIT_MASK;
196			ret = quotactl(QCMD(Q_XSETQLIM,USRQUOTA), bdev, id.uid, (caddr_t)&D);
197			break;
198#ifdef HAVE_GROUP_QUOTA
199		case SMB_GROUP_QUOTA_TYPE:
200			DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
201				path, bdev, (unsigned)id.gid));
202
203			D.d_fieldmask |= FS_DQ_LIMIT_MASK;
204			ret = quotactl(QCMD(Q_XSETQLIM,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
205			break;
206#endif /* HAVE_GROUP_QUOTA */
207		case SMB_USER_FS_QUOTA_TYPE:
208			DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
209				path, bdev, (unsigned)id.uid));
210
211			quotactl(QCMD(Q_XGETQSTAT,USRQUOTA), bdev, -1, (caddr_t)&F);
212
213			if (qflags & QUOTAS_DENY_DISK) {
214				if (!(F.qs_flags & XFS_QUOTA_UDQ_ENFD))
215					q_on |= XFS_QUOTA_UDQ_ENFD;
216				if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
217					q_on |= XFS_QUOTA_UDQ_ACCT;
218
219				if (q_on != 0) {
220					ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
221				} else {
222					ret = 0;
223				}
224
225			} else if (qflags & QUOTAS_ENABLED) {
226				if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
227					q_off |= XFS_QUOTA_UDQ_ENFD;
228
229				if (q_off != 0) {
230					ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
231				} else {
232					ret = 0;
233				}
234
235				if (!(F.qs_flags & XFS_QUOTA_UDQ_ACCT))
236					q_on |= XFS_QUOTA_UDQ_ACCT;
237
238				if (q_on != 0) {
239					ret = quotactl(QCMD(Q_XQUOTAON,USRQUOTA),bdev, -1, (caddr_t)&q_on);
240				} else {
241					ret = 0;
242				}
243			} else {
244#if 0
245			/* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
246			 * only swittching off XFS_QUOTA_UDQ_ACCT work
247			 */
248				if (F.qs_flags & XFS_QUOTA_UDQ_ENFD)
249					q_off |= XFS_QUOTA_UDQ_ENFD;
250				if (F.qs_flags & XFS_QUOTA_UDQ_ACCT)
251					q_off |= XFS_QUOTA_UDQ_ACCT;
252
253				if (q_off !=0) {
254					ret = quotactl(QCMD(Q_XQUOTAOFF,USRQUOTA),bdev, -1, (caddr_t)&q_off);
255				} else {
256					ret = 0;
257				}
258#else
259				ret = -1;
260#endif
261			}
262
263			break;
264#ifdef HAVE_GROUP_QUOTA
265		case SMB_GROUP_FS_QUOTA_TYPE:
266			DEBUG(10,("sys_set_xfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
267				path, bdev, (unsigned)id.gid));
268
269			quotactl(QCMD(Q_XGETQSTAT,GRPQUOTA), bdev, -1, (caddr_t)&F);
270
271			if (qflags & QUOTAS_DENY_DISK) {
272				if (!(F.qs_flags & XFS_QUOTA_GDQ_ENFD))
273					q_on |= XFS_QUOTA_GDQ_ENFD;
274				if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
275					q_on |= XFS_QUOTA_GDQ_ACCT;
276
277				if (q_on != 0) {
278					ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
279				} else {
280					ret = 0;
281				}
282
283			} else if (qflags & QUOTAS_ENABLED) {
284				if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
285					q_off |= XFS_QUOTA_GDQ_ENFD;
286
287				if (q_off != 0) {
288					ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
289				} else {
290					ret = 0;
291				}
292
293				if (!(F.qs_flags & XFS_QUOTA_GDQ_ACCT))
294					q_on |= XFS_QUOTA_GDQ_ACCT;
295
296				if (q_on != 0) {
297					ret = quotactl(QCMD(Q_XQUOTAON,GRPQUOTA),bdev, -1, (caddr_t)&q_on);
298				} else {
299					ret = 0;
300				}
301			} else {
302#if 0
303			/* Switch on XFS_QUOTA_UDQ_ACCT didn't work!
304			 * only swittching off XFS_QUOTA_UDQ_ACCT work
305			 */
306				if (F.qs_flags & XFS_QUOTA_GDQ_ENFD)
307					q_off |= XFS_QUOTA_GDQ_ENFD;
308				if (F.qs_flags & XFS_QUOTA_GDQ_ACCT)
309					q_off |= XFS_QUOTA_GDQ_ACCT;
310
311				if (q_off !=0) {
312					ret = quotactl(QCMD(Q_XQUOTAOFF,GRPQUOTA),bdev, -1, (caddr_t)&q_off);
313				} else {
314					ret = 0;
315				}
316#else
317				ret = -1;
318#endif
319			}
320
321			break;
322#endif /* HAVE_GROUP_QUOTA */
323		default:
324			errno = ENOSYS;
325			return -1;
326	}
327
328	return ret;
329}
330
331#else /* HAVE_XFS_QUOTAS */
332 void dummy_sysquotas_xfs(void){}
333#endif /* HAVE_XFS_QUOTAS */
334