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/>.
24 #define DBGC_CLASS DBGC_QUOTA
26 #ifndef HAVE_SYS_QUOTAS
27 #ifdef HAVE_QUOTACTL_LINUX
28 #undef HAVE_QUOTACTL_LINUX
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
)
43 struct v1_kern_dqblk D
;
44 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
) {
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
) {
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
;
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
;
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
;
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
)
110 struct v1_kern_dqblk D
;
111 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
;
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
;
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
);
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
);
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
;
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
;
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
)
173 struct v2_kern_dqblk D
;
174 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
) {
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
) {
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
;
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
;
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
;
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
)
240 struct v2_kern_dqblk D
;
241 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
;
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
;
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
);
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
);
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
;
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
;
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
)
304 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
) {
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
) {
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
;
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
;
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
;
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
)
371 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
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
;
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
;
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
);
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
);
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
;
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
;
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
)
434 if (!path
||!bdev
||!dp
)
435 smb_panic("sys_set_vfs_quota: called with NULL pointer");
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
) {
451 if ((dp
->curblocks
==0)&&
453 (dp
->hardlimit
==0)) {
454 /* the upper layer functions don't want empty quota records...*/
459 case SMB_USER_FS_QUOTA_TYPE
:
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
);
470 case SMB_GROUP_FS_QUOTA_TYPE
:
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
);
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
)
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
;
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
))) {
513 case SMB_USER_FS_QUOTA_TYPE
:
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
) {
528 case SMB_GROUP_FS_QUOTA_TYPE
:
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
) {
552 #else /* HAVE_QUOTACTL_LINUX */
553 void dummy_sysquotas_linux(void);
555 void dummy_sysquotas_linux(void){}
556 #endif /* HAVE_QUOTACTL_LINUX */