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