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
)
111 uint32 oldqflags
= 0;
112 struct v1_kern_dqblk D
;
113 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
117 if (bsize
== dp
->bsize
) {
118 D
.dqb_bsoftlimit
= dp
->softlimit
;
119 D
.dqb_bhardlimit
= dp
->hardlimit
;
120 D
.dqb_ihardlimit
= dp
->ihardlimit
;
121 D
.dqb_isoftlimit
= dp
->isoftlimit
;
123 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
124 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
125 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
126 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
132 case SMB_USER_QUOTA_TYPE
:
133 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
134 path
, bdev
, (unsigned)id
.uid
));
136 ret
= quotactl(QCMD(Q_V1_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
138 case SMB_GROUP_QUOTA_TYPE
:
139 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
140 path
, bdev
, (unsigned)id
.gid
));
142 ret
= quotactl(QCMD(Q_V1_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
144 case SMB_USER_FS_QUOTA_TYPE
:
145 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
146 path
, bdev
, (unsigned)id
.uid
));
148 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
149 oldqflags
|= QUOTAS_DENY_DISK
;
153 case SMB_GROUP_FS_QUOTA_TYPE
:
154 DEBUG(10,("sys_set_linux_v1_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
155 path
, bdev
, (unsigned)id
.gid
));
157 if ((ret
= quotactl(QCMD(Q_V1_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
158 oldqflags
|= QUOTAS_DENY_DISK
;
170 /****************************************************************************
171 Abstract out the v2 Linux quota get calls.
172 ****************************************************************************/
173 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
)
177 struct v2_kern_dqblk D
;
178 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
183 case SMB_USER_QUOTA_TYPE
:
184 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
185 path
, bdev
, (unsigned)id
.uid
));
187 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
192 case SMB_GROUP_QUOTA_TYPE
:
193 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
194 path
, bdev
, (unsigned)id
.gid
));
196 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
201 case SMB_USER_FS_QUOTA_TYPE
:
202 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
203 path
, bdev
, (unsigned)id
.uid
));
205 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
206 qflags
|= QUOTAS_DENY_DISK
;
210 case SMB_GROUP_FS_QUOTA_TYPE
:
211 DEBUG(10,("sys_get_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
212 path
, bdev
, (unsigned)id
.gid
));
214 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
215 qflags
|= QUOTAS_DENY_DISK
;
225 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
226 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
227 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
228 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
229 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
230 dp
->curblocks
= (uint64_t)D
.dqb_curspace
/bsize
;
238 /****************************************************************************
239 Abstract out the v2 Linux quota set calls.
240 ****************************************************************************/
241 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
)
245 uint32 oldqflags
= 0;
246 struct v2_kern_dqblk D
;
247 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
251 if (bsize
== dp
->bsize
) {
252 D
.dqb_bsoftlimit
= dp
->softlimit
;
253 D
.dqb_bhardlimit
= dp
->hardlimit
;
254 D
.dqb_ihardlimit
= dp
->ihardlimit
;
255 D
.dqb_isoftlimit
= dp
->isoftlimit
;
257 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
258 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
259 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
260 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
266 case SMB_USER_QUOTA_TYPE
:
267 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
268 path
, bdev
, (unsigned)id
.uid
));
270 ret
= quotactl(QCMD(Q_V2_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
272 case SMB_GROUP_QUOTA_TYPE
:
273 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
274 path
, bdev
, (unsigned)id
.gid
));
276 ret
= quotactl(QCMD(Q_V2_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
278 case SMB_USER_FS_QUOTA_TYPE
:
279 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
280 path
, bdev
, (unsigned)id
.uid
));
282 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
283 oldqflags
|= QUOTAS_DENY_DISK
;
287 case SMB_GROUP_FS_QUOTA_TYPE
:
288 DEBUG(10,("sys_set_linux_v2_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
289 path
, bdev
, (unsigned)id
.gid
));
291 if ((ret
= quotactl(QCMD(Q_V2_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
292 oldqflags
|= QUOTAS_DENY_DISK
;
304 /****************************************************************************
305 Abstract out the generic Linux quota get calls.
306 ****************************************************************************/
307 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
)
312 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
317 case SMB_USER_QUOTA_TYPE
:
318 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
319 path
, bdev
, (unsigned)id
.uid
));
321 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
326 case SMB_GROUP_QUOTA_TYPE
:
327 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
328 path
, bdev
, (unsigned)id
.gid
));
330 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))&&errno
!= EDQUOT
) {
335 case SMB_USER_FS_QUOTA_TYPE
:
336 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
337 path
, bdev
, (unsigned)id
.uid
));
339 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
340 qflags
|= QUOTAS_DENY_DISK
;
344 case SMB_GROUP_FS_QUOTA_TYPE
:
345 DEBUG(10,("sys_get_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
346 path
, bdev
, (unsigned)id
.gid
));
348 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
349 qflags
|= QUOTAS_DENY_DISK
;
359 dp
->softlimit
= (uint64_t)D
.dqb_bsoftlimit
;
360 dp
->hardlimit
= (uint64_t)D
.dqb_bhardlimit
;
361 dp
->ihardlimit
= (uint64_t)D
.dqb_ihardlimit
;
362 dp
->isoftlimit
= (uint64_t)D
.dqb_isoftlimit
;
363 dp
->curinodes
= (uint64_t)D
.dqb_curinodes
;
364 dp
->curblocks
= (uint64_t)D
.dqb_curspace
/bsize
;
372 /****************************************************************************
373 Abstract out the gen Linux quota set calls.
374 ****************************************************************************/
375 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
)
379 uint32 oldqflags
= 0;
381 uint64_t bsize
= (uint64_t)QUOTABLOCK_SIZE
;
385 if (bsize
== dp
->bsize
) {
386 D
.dqb_bsoftlimit
= dp
->softlimit
;
387 D
.dqb_bhardlimit
= dp
->hardlimit
;
388 D
.dqb_ihardlimit
= dp
->ihardlimit
;
389 D
.dqb_isoftlimit
= dp
->isoftlimit
;
391 D
.dqb_bsoftlimit
= (dp
->softlimit
*dp
->bsize
)/bsize
;
392 D
.dqb_bhardlimit
= (dp
->hardlimit
*dp
->bsize
)/bsize
;
393 D
.dqb_ihardlimit
= (dp
->ihardlimit
*dp
->bsize
)/bsize
;
394 D
.dqb_isoftlimit
= (dp
->isoftlimit
*dp
->bsize
)/bsize
;
396 D
.dqb_valid
= QIF_LIMITS
;
401 case SMB_USER_QUOTA_TYPE
:
402 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_QUOTA_TYPE uid[%u]\n",
403 path
, bdev
, (unsigned)id
.uid
));
405 ret
= quotactl(QCMD(Q_SETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
);
407 case SMB_GROUP_QUOTA_TYPE
:
408 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_QUOTA_TYPE gid[%u]\n",
409 path
, bdev
, (unsigned)id
.gid
));
411 ret
= quotactl(QCMD(Q_SETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
);
413 case SMB_USER_FS_QUOTA_TYPE
:
414 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_USER_FS_QUOTA_TYPE (uid[%u])\n",
415 path
, bdev
, (unsigned)id
.uid
));
417 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,USRQUOTA
), bdev
, id
.uid
, (caddr_t
)&D
))==0) {
418 oldqflags
|= QUOTAS_DENY_DISK
;
422 case SMB_GROUP_FS_QUOTA_TYPE
:
423 DEBUG(10,("sys_set_linux_gen_quota: path[%s] bdev[%s] SMB_GROUP_FS_QUOTA_TYPE (gid[%u])\n",
424 path
, bdev
, (unsigned)id
.gid
));
426 if ((ret
= quotactl(QCMD(Q_GETQUOTA
,GRPQUOTA
), bdev
, id
.gid
, (caddr_t
)&D
))==0) {
427 oldqflags
|= QUOTAS_DENY_DISK
;
439 /****************************************************************************
440 Abstract out the Linux quota get calls.
441 ****************************************************************************/
442 int sys_get_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
446 if (!path
||!bdev
||!dp
)
447 smb_panic("sys_set_vfs_quota: called with NULL pointer");
453 case SMB_USER_QUOTA_TYPE
:
454 case SMB_GROUP_QUOTA_TYPE
:
455 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
456 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
457 if ((ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
463 if ((dp
->curblocks
==0)&&
465 (dp
->hardlimit
==0)) {
466 /* the upper layer functions don't want empty quota records...*/
471 case SMB_USER_FS_QUOTA_TYPE
:
474 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
475 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
476 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
482 case SMB_GROUP_FS_QUOTA_TYPE
:
485 if ((ret
=sys_get_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
486 if ((ret
=sys_get_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))&&errno
!= EDQUOT
) {
487 ret
=sys_get_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
501 /****************************************************************************
502 Abstract out the Linux quota set calls.
503 ****************************************************************************/
504 int sys_set_vfs_quota(const char *path
, const char *bdev
, enum SMB_QUOTA_TYPE qtype
, unid_t id
, SMB_DISK_QUOTA
*dp
)
507 uint32 oldqflags
= 0;
509 if (!path
||!bdev
||!dp
)
510 smb_panic("sys_set_vfs_quota: called with NULL pointer");
512 oldqflags
= dp
->qflags
;
515 case SMB_USER_QUOTA_TYPE
:
516 case SMB_GROUP_QUOTA_TYPE
:
517 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
518 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
519 if ((ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
))) {
525 case SMB_USER_FS_QUOTA_TYPE
:
528 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
529 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
530 ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
534 if (oldqflags
== dp
->qflags
) {
540 case SMB_GROUP_FS_QUOTA_TYPE
:
543 if ((ret
=sys_set_linux_gen_quota(path
, bdev
, qtype
, id
, dp
))) {
544 if ((ret
=sys_set_linux_v2_quota(path
, bdev
, qtype
, id
, dp
))) {
545 ret
=sys_set_linux_v1_quota(path
, bdev
, qtype
, id
, dp
);
549 if (oldqflags
== dp
->qflags
) {
564 #else /* HAVE_QUOTACTL_LINUX */
565 void dummy_sysquotas_linux(void);
567 void dummy_sysquotas_linux(void){}
568 #endif /* HAVE_QUOTACTL_LINUX */