c02b638648026d086f97dd8793139aa471d507ca
[samba.git] / source3 / lib / sysquotas_4A.c
1 /* 
2    Unix SMB/CIFS implementation.
3    System QUOTA function wrappers for QUOTACTL_4A
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, 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_QUOTACTL_4A
29 #undef HAVE_QUOTACTL_4A
30 #endif
31 #endif
32
33 #ifdef HAVE_QUOTACTL_4A
34 /* long quotactl(int cmd, char *special, qid_t id, caddr_t addr) */
35 /* this is used by: HPUX,IRIX */
36
37 #ifdef HAVE_SYS_TYPES_H
38 #include <sys/types.h>
39 #endif
40
41 #ifdef HAVE_ASM_TYPES_H
42 #include <asm/types.h>
43 #endif
44
45 #ifdef HAVE_SYS_QUOTA_H
46 #include <sys/quota.h>
47 #endif
48
49 #ifndef Q_SETQLIM
50 #define Q_SETQLIM Q_SETQUOTA
51 #endif
52
53 #ifndef QCMD
54 #define QCMD(x,y) x
55 #endif
56
57 #ifndef QCMD
58 #define QCMD(x,y) x
59 #endif
60
61 #ifdef GRPQUOTA
62 #define HAVE_GROUP_QUOTA
63 #endif
64
65 #ifndef QUOTABLOCK_SIZE
66 #define QUOTABLOCK_SIZE DEV_BSIZE
67 #endif
68
69 #ifdef HAVE_DQB_FSOFTLIMIT
70 #define dqb_isoftlimit  dqb_fsoftlimit
71 #define dqb_ihardlimit  dqb_fhardlimit
72 #define dqb_curinodes   dqb_curfiles
73 #endif
74
75 #ifdef INITQFNAMES
76 #define USERQUOTAFILE_EXTENSION ".user"
77 #else
78 #define USERQUOTAFILE_EXTENSION ""
79 #endif
80
81 #if !defined(QUOTAFILENAME) && defined(QFILENAME)
82 #define QUOTAFILENAME QFILENAME
83 #endif
84
85 /****************************************************************************
86  Abstract out the quotactl_4A get calls.
87 ****************************************************************************/
88 int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
89 {
90         int ret = -1;
91         uint32 qflags = 0;
92         struct dqblk D;
93         SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
94
95         ZERO_STRUCT(D);
96         ZERO_STRUCT(*dp);
97         dp->qtype = qtype;
98
99         switch (qtype) {
100                 case SMB_USER_QUOTA_TYPE:
101                         DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
102                                 path, bdev, (unsigned)id.uid));
103
104                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))&&errno != EDQUOT) {
105                                 return ret;
106                         }
107
108                         if ((D.dqb_curblocks==0)&&
109                                 (D.dqb_bsoftlimit==0)&&
110                                 (D.dqb_bhardlimit==0)) {
111                                 /* the upper layer functions don't want empty quota records...*/
112                                 return -1;
113                         }
114
115                         break;
116 #ifdef HAVE_GROUP_QUOTA
117                 case SMB_GROUP_QUOTA_TYPE:
118                         DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
119                                 path, bdev, (unsigned)id.gid));
120
121                         if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))&&errno != EDQUOT) {
122                                 return ret;
123                         }
124
125                         if ((D.dqb_curblocks==0)&&
126                                 (D.dqb_bsoftlimit==0)&&
127                                 (D.dqb_bhardlimit==0)) {
128                                 /* the upper layer functions don't want empty quota records...*/
129                                 return -1;
130                         }
131
132                         break;
133 #endif /* HAVE_GROUP_QUOTA */
134                 case SMB_USER_FS_QUOTA_TYPE:
135                         id.uid = getuid();
136
137                         DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
138                                 path, (caddr_t)bdev, (unsigned)id.uid));
139
140                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) {
141                                 qflags |= QUOTAS_DENY_DISK;
142                         }
143
144                         ret = 0;
145                         break;
146 #ifdef HAVE_GROUP_QUOTA
147                 case SMB_GROUP_FS_QUOTA_TYPE:
148                         id.gid = getgid();
149
150                         DEBUG(10,("sys_get_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
151                                 path, bdev, (unsigned)id.gid));
152
153                         if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) {
154                                 qflags |= QUOTAS_DENY_DISK;
155                         }
156
157                         ret = 0;
158                         break;
159 #endif /* HAVE_GROUP_QUOTA */
160                 default:
161                         errno = ENOSYS;
162                         return -1;
163         }
164
165         dp->bsize = bsize;
166         dp->softlimit = (SMB_BIG_UINT)D.dqb_bsoftlimit;
167         dp->hardlimit = (SMB_BIG_UINT)D.dqb_bhardlimit;
168         dp->ihardlimit = (SMB_BIG_UINT)D.dqb_ihardlimit;
169         dp->isoftlimit = (SMB_BIG_UINT)D.dqb_isoftlimit;
170         dp->curinodes = (SMB_BIG_UINT)D.dqb_curinodes;
171         dp->curblocks = (SMB_BIG_UINT)D.dqb_curblocks;
172
173
174         dp->qflags = qflags;
175
176         return ret;
177 }
178
179 /****************************************************************************
180  Abstract out the quotactl_4A set calls.
181 ****************************************************************************/
182 int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
183 {
184         int ret = -1;
185         uint32 qflags = 0;
186         uint32 oldqflags = 0;
187         struct dqblk D;
188         SMB_BIG_UINT bsize = (SMB_BIG_UINT)QUOTABLOCK_SIZE;
189
190         ZERO_STRUCT(D);
191
192         if (bsize == dp->bsize) {
193                 D.dqb_bsoftlimit = dp->softlimit;
194                 D.dqb_bhardlimit = dp->hardlimit;
195                 D.dqb_ihardlimit = dp->ihardlimit;
196                 D.dqb_isoftlimit = dp->isoftlimit;
197         } else {
198                 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
199                 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
200                 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
201                 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
202         }
203
204         qflags = dp->qflags;
205
206         switch (qtype) {
207                 case SMB_USER_QUOTA_TYPE:
208                         DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
209                                 path, bdev, (unsigned)id.uid));
210
211                         ret = quotactl(QCMD(Q_SETQLIM,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D);
212                         break;
213 #ifdef HAVE_GROUP_QUOTA
214                 case SMB_GROUP_QUOTA_TYPE:
215                         DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
216                                 path, bdev, (unsigned)id.gid));
217
218                         ret = quotactl(QCMD(Q_SETQLIM,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D);
219                         break;
220 #endif /* HAVE_GROUP_QUOTA */
221                 case SMB_USER_FS_QUOTA_TYPE:
222                         /* this stuff didn't work as it should:
223                          * switching on/off quota via quotactl()
224                          * didn't work!
225                          * So we just return 0
226                          * --metze
227                          * 
228                          * On HPUX we didn't have the mount path,
229                          * we need to fix sys_path_to_bdev()
230                          *
231                          */
232                         id.uid = getuid();
233                         DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
234                                 path, bdev, (unsigned)id.uid));
235
236 #if 0
237                         ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D);
238
239                         if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
240                                 if (ret == 0) {
241                                         char *quota_file = NULL;
242                                         
243                                         asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,USERQUOTAFILE_EXTENSION);
244                                         if (quota_file == NULL) {
245                                                 DEBUG(0,("asprintf() failed!\n"));
246                                                 errno = ENOMEM;
247                                                 return -1;
248                                         }
249                                         
250                                         ret = quotactl(QCMD(Q_QUOTAON,USRQUOTA), (caddr_t)bdev, -1,(void *)quota_file);
251                                 } else {
252                                         ret = 0;        
253                                 }
254                         } else {
255                                 if (ret != 0) {
256                                         /* turn off */
257                                         ret = quotactl(QCMD(Q_QUOTAOFF,USRQUOTA), (caddr_t)bdev, -1, (void *)0);        
258                                 } else {
259                                         ret = 0;
260                                 }               
261                         }
262
263                         DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
264                                 ret,errno,strerror(errno),id.uid,bdev));
265 #else
266                         if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), (caddr_t)bdev, id.uid, (void *)&D))==0) {
267                                 oldqflags |= QUOTAS_DENY_DISK;
268                         }
269
270                         if (oldqflags == qflags) {
271                                 ret = 0;
272                         } else {
273                                 ret = -1;
274                         }
275 #endif
276                         break;
277 #ifdef HAVE_GROUP_QUOTA
278                 case SMB_GROUP_FS_QUOTA_TYPE:
279                         /* this stuff didn't work as it should:
280                          * switching on/off quota via quotactl()
281                          * didn't work!
282                          * So we just return 0
283                          * --metze
284                          * 
285                          * On HPUX we didn't have the mount path,
286                          * we need to fix sys_path_to_bdev()
287                          *
288                          */
289                         id.gid = getgid();
290                         DEBUG(10,("sys_set_vfs_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
291                                 path, bdev, (unsigned)id.gid));
292
293 #if 0
294                         ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id, (void *)&D);
295
296                         if ((qflags&QUOTAS_DENY_DISK)||(qflags&QUOTAS_ENABLED)) {
297                                 if (ret == 0) {
298                                         char *quota_file = NULL;
299                                         
300                                         asprintf(&quota_file,"/%s/%s%s",path, QUOTAFILENAME,GROUPQUOTAFILE_EXTENSION);
301                                         if (quota_file == NULL) {
302                                                 DEBUG(0,("asprintf() failed!\n"));
303                                                 errno = ENOMEM;
304                                                 return -1;
305                                         }
306                                         
307                                         ret = quotactl(QCMD(Q_QUOTAON,GRPQUOTA), (caddr_t)bdev, -1,(void *)quota_file);
308                                 } else {
309                                         ret = 0;        
310                                 }
311                         } else {
312                                 if (ret != 0) {
313                                         /* turn off */
314                                         ret = quotactl(QCMD(Q_QUOTAOFF,GRPQUOTA), (caddr_t)bdev, -1, (void *)0);        
315                                 } else {
316                                         ret = 0;
317                                 }               
318                         }
319
320                         DEBUG(0,("sys_set_vfs_quota: ret(%d) errno(%d)[%s] uid(%d) bdev[%s]\n",
321                                 ret,errno,strerror(errno),id.gid,bdev));
322 #else
323                         if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), (caddr_t)bdev, id.gid, (void *)&D))==0) {
324                                 oldqflags |= QUOTAS_DENY_DISK;
325                         }
326
327                         if (oldqflags == qflags) {
328                                 ret = 0;
329                         } else {
330                                 ret = -1;
331                         }
332 #endif
333                         break;
334 #endif /* HAVE_GROUP_QUOTA */
335                 default:
336                         errno = ENOSYS;
337                         return -1;
338         }
339
340         return ret;
341 }
342
343 #else /* HAVE_QUOTACTL_4A */
344  void dummy_sysquotas_4A(void);
345
346  void dummy_sysquotas_4A(void){}
347 #endif /* HAVE_QUOTACTL_4A */