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