negoex.idl: use DATA_BLOB for negoex_BYTE_VECTOR
[Samba.git] / source3 / lib / sysquotas_linux.c
blobbf3504ae03c141a5f2437d987c99837ecf146272
1 /*
2 Unix SMB/CIFS implementation.
3 System QUOTA function wrappers for LINUX
4 Copyright (C) Stefan (metze) Metzmacher 2003
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.
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.
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/>.
21 #include "includes.h"
23 #undef DBGC_CLASS
24 #define DBGC_CLASS DBGC_QUOTA
26 #ifndef HAVE_SYS_QUOTAS
27 #ifdef HAVE_QUOTACTL_LINUX
28 #undef HAVE_QUOTACTL_LINUX
29 #endif
30 #endif
32 #ifdef HAVE_QUOTACTL_LINUX
34 #include "samba_linux_quota.h"
36 /****************************************************************************
37 Abstract out the v1 Linux quota get calls.
38 ****************************************************************************/
39 static int sys_get_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
41 int ret = -1;
42 uint32_t qflags = 0;
43 struct v1_kern_dqblk D;
44 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
46 ZERO_STRUCT(D);
48 switch (qtype) {
49 case SMB_USER_QUOTA_TYPE:
50 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
51 path, bdev, (unsigned)id.uid));
53 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
54 return ret;
57 break;
58 case SMB_GROUP_QUOTA_TYPE:
59 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
60 path, bdev, (unsigned)id.gid));
62 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
63 return ret;
66 break;
67 case SMB_USER_FS_QUOTA_TYPE:
68 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
69 path, bdev, (unsigned)id.uid));
71 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
72 qflags |= QUOTAS_DENY_DISK;
75 break;
76 case SMB_GROUP_FS_QUOTA_TYPE:
77 DEBUG(10,("sys_get_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
78 path, bdev, (unsigned)id.gid));
80 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
81 qflags |= QUOTAS_DENY_DISK;
84 break;
85 default:
86 errno = ENOSYS;
87 return -1;
90 dp->bsize = bsize;
91 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
92 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
93 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
94 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
95 dp->curinodes = (uint64_t)D.dqb_curinodes;
96 dp->curblocks = (uint64_t)D.dqb_curblocks;
99 dp->qflags = qflags;
101 return ret;
104 /****************************************************************************
105 Abstract out the v1 Linux quota set calls.
106 ****************************************************************************/
107 static int sys_set_linux_v1_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
109 int ret = -1;
110 struct v1_kern_dqblk D;
111 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
113 ZERO_STRUCT(D);
115 if (bsize == dp->bsize) {
116 D.dqb_bsoftlimit = dp->softlimit;
117 D.dqb_bhardlimit = dp->hardlimit;
118 D.dqb_ihardlimit = dp->ihardlimit;
119 D.dqb_isoftlimit = dp->isoftlimit;
120 } else {
121 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
122 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
123 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
124 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
127 switch (qtype) {
128 case SMB_USER_QUOTA_TYPE:
129 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
130 path, bdev, (unsigned)id.uid));
132 ret = quotactl(QCMD(Q_V1_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
133 break;
134 case SMB_GROUP_QUOTA_TYPE:
135 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
136 path, bdev, (unsigned)id.gid));
138 ret = quotactl(QCMD(Q_V1_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
139 break;
140 case SMB_USER_FS_QUOTA_TYPE:
141 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
142 path, bdev, (unsigned)id.uid));
144 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
145 dp->qflags |= QUOTAS_DENY_DISK;
148 break;
149 case SMB_GROUP_FS_QUOTA_TYPE:
150 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
151 path, bdev, (unsigned)id.gid));
153 if ((ret = quotactl(QCMD(Q_V1_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
154 dp->qflags |= QUOTAS_DENY_DISK;
157 break;
158 default:
159 errno = ENOSYS;
160 return -1;
163 return ret;
166 /****************************************************************************
167 Abstract out the v2 Linux quota get calls.
168 ****************************************************************************/
169 static int sys_get_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
171 int ret = -1;
172 uint32_t qflags = 0;
173 struct v2_kern_dqblk D;
174 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
176 ZERO_STRUCT(D);
178 switch (qtype) {
179 case SMB_USER_QUOTA_TYPE:
180 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
181 path, bdev, (unsigned)id.uid));
183 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
184 return ret;
187 break;
188 case SMB_GROUP_QUOTA_TYPE:
189 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
190 path, bdev, (unsigned)id.gid));
192 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
193 return ret;
196 break;
197 case SMB_USER_FS_QUOTA_TYPE:
198 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
199 path, bdev, (unsigned)id.uid));
201 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
202 qflags |= QUOTAS_DENY_DISK;
205 break;
206 case SMB_GROUP_FS_QUOTA_TYPE:
207 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
208 path, bdev, (unsigned)id.gid));
210 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
211 qflags |= QUOTAS_DENY_DISK;
214 break;
215 default:
216 errno = ENOSYS;
217 return -1;
220 dp->bsize = bsize;
221 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
222 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
223 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
224 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
225 dp->curinodes = (uint64_t)D.dqb_curinodes;
226 dp->curblocks = (uint64_t)D.dqb_curspace/bsize;
229 dp->qflags = qflags;
231 return ret;
234 /****************************************************************************
235 Abstract out the v2 Linux quota set calls.
236 ****************************************************************************/
237 static int sys_set_linux_v2_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
239 int ret = -1;
240 struct v2_kern_dqblk D;
241 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
243 ZERO_STRUCT(D);
245 if (bsize == dp->bsize) {
246 D.dqb_bsoftlimit = dp->softlimit;
247 D.dqb_bhardlimit = dp->hardlimit;
248 D.dqb_ihardlimit = dp->ihardlimit;
249 D.dqb_isoftlimit = dp->isoftlimit;
250 } else {
251 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
252 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
253 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
254 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
257 switch (qtype) {
258 case SMB_USER_QUOTA_TYPE:
259 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
260 path, bdev, (unsigned)id.uid));
262 ret = quotactl(QCMD(Q_V2_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
263 break;
264 case SMB_GROUP_QUOTA_TYPE:
265 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
266 path, bdev, (unsigned)id.gid));
268 ret = quotactl(QCMD(Q_V2_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
269 break;
270 case SMB_USER_FS_QUOTA_TYPE:
271 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
272 path, bdev, (unsigned)id.uid));
274 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
275 dp->qflags |= QUOTAS_DENY_DISK;
278 break;
279 case SMB_GROUP_FS_QUOTA_TYPE:
280 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
281 path, bdev, (unsigned)id.gid));
283 if ((ret = quotactl(QCMD(Q_V2_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
284 dp->qflags |= QUOTAS_DENY_DISK;
287 break;
288 default:
289 errno = ENOSYS;
290 return -1;
293 return ret;
296 /****************************************************************************
297 Abstract out the generic Linux quota get calls.
298 ****************************************************************************/
299 static int sys_get_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
301 int ret = -1;
302 uint32_t qflags = 0;
303 struct if_dqblk D;
304 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
306 ZERO_STRUCT(D);
308 switch (qtype) {
309 case SMB_USER_QUOTA_TYPE:
310 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
311 path, bdev, (unsigned)id.uid));
313 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))&&errno != EDQUOT) {
314 return ret;
317 break;
318 case SMB_GROUP_QUOTA_TYPE:
319 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
320 path, bdev, (unsigned)id.gid));
322 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))&&errno != EDQUOT) {
323 return ret;
326 break;
327 case SMB_USER_FS_QUOTA_TYPE:
328 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
329 path, bdev, (unsigned)id.uid));
331 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
332 qflags |= QUOTAS_DENY_DISK;
335 break;
336 case SMB_GROUP_FS_QUOTA_TYPE:
337 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
338 path, bdev, (unsigned)id.gid));
340 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
341 qflags |= QUOTAS_DENY_DISK;
344 break;
345 default:
346 errno = ENOSYS;
347 return -1;
350 dp->bsize = bsize;
351 dp->softlimit = (uint64_t)D.dqb_bsoftlimit;
352 dp->hardlimit = (uint64_t)D.dqb_bhardlimit;
353 dp->ihardlimit = (uint64_t)D.dqb_ihardlimit;
354 dp->isoftlimit = (uint64_t)D.dqb_isoftlimit;
355 dp->curinodes = (uint64_t)D.dqb_curinodes;
356 dp->curblocks = (uint64_t)D.dqb_curspace/bsize;
359 dp->qflags = qflags;
361 return ret;
364 /****************************************************************************
365 Abstract out the gen Linux quota set calls.
366 ****************************************************************************/
367 static int sys_set_linux_gen_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
369 int ret = -1;
370 struct if_dqblk D;
371 uint64_t bsize = (uint64_t)QUOTABLOCK_SIZE;
373 ZERO_STRUCT(D);
375 if (bsize == dp->bsize) {
376 D.dqb_bsoftlimit = dp->softlimit;
377 D.dqb_bhardlimit = dp->hardlimit;
378 D.dqb_ihardlimit = dp->ihardlimit;
379 D.dqb_isoftlimit = dp->isoftlimit;
380 } else {
381 D.dqb_bsoftlimit = (dp->softlimit*dp->bsize)/bsize;
382 D.dqb_bhardlimit = (dp->hardlimit*dp->bsize)/bsize;
383 D.dqb_ihardlimit = (dp->ihardlimit*dp->bsize)/bsize;
384 D.dqb_isoftlimit = (dp->isoftlimit*dp->bsize)/bsize;
386 D.dqb_valid = QIF_LIMITS;
388 switch (qtype) {
389 case SMB_USER_QUOTA_TYPE:
390 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
391 path, bdev, (unsigned)id.uid));
393 ret = quotactl(QCMD(Q_SETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D);
394 break;
395 case SMB_GROUP_QUOTA_TYPE:
396 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
397 path, bdev, (unsigned)id.gid));
399 ret = quotactl(QCMD(Q_SETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D);
400 break;
401 case SMB_USER_FS_QUOTA_TYPE:
402 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
403 path, bdev, (unsigned)id.uid));
405 if ((ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), bdev, id.uid, (caddr_t)&D))==0) {
406 dp->qflags |= QUOTAS_DENY_DISK;
409 break;
410 case SMB_GROUP_FS_QUOTA_TYPE:
411 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
412 path, bdev, (unsigned)id.gid));
414 if ((ret = quotactl(QCMD(Q_GETQUOTA,GRPQUOTA), bdev, id.gid, (caddr_t)&D))==0) {
415 dp->qflags |= QUOTAS_DENY_DISK;
418 break;
419 default:
420 errno = ENOSYS;
421 return -1;
424 return ret;
427 /****************************************************************************
428 Abstract out the Linux quota get calls.
429 ****************************************************************************/
430 int sys_get_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
432 int ret = -1;
434 if (!path||!bdev||!dp)
435 smb_panic("sys_set_vfs_quota: called with NULL pointer");
437 ZERO_STRUCT(*dp);
438 dp->qtype = qtype;
440 switch (qtype) {
441 case SMB_USER_QUOTA_TYPE:
442 case SMB_GROUP_QUOTA_TYPE:
443 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
444 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
445 if ((ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
446 return ret;
451 if ((dp->curblocks==0)&&
452 (dp->softlimit==0)&&
453 (dp->hardlimit==0)) {
454 /* the upper layer functions don't want empty quota records...*/
455 return -1;
458 break;
459 case SMB_USER_FS_QUOTA_TYPE:
460 id.uid = getuid();
462 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
463 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
464 ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
468 ret = 0;
469 break;
470 case SMB_GROUP_FS_QUOTA_TYPE:
471 id.gid = getgid();
473 if ((ret=sys_get_linux_gen_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
474 if ((ret=sys_get_linux_v2_quota(path, bdev, qtype, id, dp))&&errno != EDQUOT) {
475 ret=sys_get_linux_v1_quota(path, bdev, qtype, id, dp);
479 ret = 0;
480 break;
481 default:
482 errno = ENOSYS;
483 return -1;
486 return ret;
489 /****************************************************************************
490 Abstract out the Linux quota set calls.
491 ****************************************************************************/
492 int sys_set_vfs_quota(const char *path, const char *bdev, enum SMB_QUOTA_TYPE qtype, unid_t id, SMB_DISK_QUOTA *dp)
494 int ret = -1;
495 uint32_t oldqflags = 0;
497 if (!path||!bdev||!dp)
498 smb_panic("sys_set_vfs_quota: called with NULL pointer");
500 oldqflags = dp->qflags;
502 switch (qtype) {
503 case SMB_USER_QUOTA_TYPE:
504 case SMB_GROUP_QUOTA_TYPE:
505 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
506 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
507 if ((ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp))) {
508 return ret;
512 break;
513 case SMB_USER_FS_QUOTA_TYPE:
514 id.uid = getuid();
516 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
517 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
518 ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
522 if (oldqflags == dp->qflags) {
523 ret = 0;
524 } else {
525 ret = -1;
527 break;
528 case SMB_GROUP_FS_QUOTA_TYPE:
529 id.gid = getgid();
531 if ((ret=sys_set_linux_gen_quota(path, bdev, qtype, id, dp))) {
532 if ((ret=sys_set_linux_v2_quota(path, bdev, qtype, id, dp))) {
533 ret=sys_set_linux_v1_quota(path, bdev, qtype, id, dp);
537 if (oldqflags == dp->qflags) {
538 ret = 0;
539 } else {
540 ret = -1;
543 break;
544 default:
545 errno = ENOSYS;
546 return -1;
549 return ret;
552 #else /* HAVE_QUOTACTL_LINUX */
553 void dummy_sysquotas_linux(void);
555 void dummy_sysquotas_linux(void){}
556 #endif /* HAVE_QUOTACTL_LINUX */