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