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