2012-07-01 16:35:55 +04:00
/*
* Unix SMB / CIFS implementation .
* System QUOTA function wrappers for QUOTACTL_4B
* Copyright ( C ) 2011 James Peach .
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program ; if not , write to the Free Software
* Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_QUOTA
# ifndef HAVE_SYS_QUOTAS
# undef HAVE_QUOTACTL_4B
# endif
# ifdef HAVE_QUOTACTL_4B
/* int quotactl(const char *path, int cmd, int id, char *addr)
*
* This is used by many ( all ? ) BSD - derived systems . This implementation has
* been developed and tested on Darwin , but may also work on other BSD systems .
*/
# ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
# endif
# ifdef HAVE_SYS_QUOTA_H
# include <sys/quota.h>
# endif
2012-09-02 18:08:58 +04:00
# ifdef HAVE_UFS_UFS_QUOTA_H
# include <ufs/ufs/quota.h>
# endif
# if defined(DARWINOS)
/* WorkARound broken HFS access checks in hfs_quotactl. Darwin only(?) */
2012-07-01 16:35:55 +04:00
# define HFS_QUOTACTL_WAR 1
2012-09-02 18:08:58 +04:00
# endif
2012-07-01 16:35:55 +04:00
static void xlate_qblk_to_smb ( const struct dqblk * const qblk ,
SMB_DISK_QUOTA * dp )
{
ZERO_STRUCTP ( dp ) ;
DEBUG ( 10 , ( " unix softlimit=%u hardlimit=%u curblock=%u \n " ,
( unsigned ) qblk - > dqb_bsoftlimit , ( unsigned ) qblk - > dqb_bhardlimit ,
2012-09-02 18:08:58 +04:00
# ifdef HAVE_STRUCT_DQBLK_DQB_CURBYTES
2012-07-01 16:35:55 +04:00
( unsigned ) qblk - > dqb_curbytes ) ) ;
2012-09-02 18:08:58 +04:00
# else
( unsigned ) qblk - > dqb_curblocks ) ) ;
# endif
2012-07-01 16:35:55 +04:00
DEBUGADD ( 10 , ( " unix softinodes=%u hardinodes=%u curinodes=%u \n " ,
( unsigned ) qblk - > dqb_isoftlimit , ( unsigned ) qblk - > dqb_ihardlimit ,
( unsigned ) qblk - > dqb_curinodes ) ) ;
2012-09-02 18:08:58 +04:00
# ifdef HAVE_STRUCT_DQBLK_DQB_CURBYTES
2012-07-01 16:35:55 +04:00
/* On Darwin, quotas are counted in bytes. We report them
* in 512 b blocks because various callers have assumptions
* about the block size .
*/
# define XLATE_TO_BLOCKS(bytes) (((bytes) + 1) / 512)
dp - > bsize = 512 ;
dp - > softlimit = XLATE_TO_BLOCKS ( qblk - > dqb_bsoftlimit ) ;
dp - > hardlimit = XLATE_TO_BLOCKS ( qblk - > dqb_bhardlimit ) ;
dp - > curblocks = XLATE_TO_BLOCKS ( qblk - > dqb_curbytes ) ;
# undef XLATE_TO_BLOCKS
2012-09-02 18:08:58 +04:00
# endif
2012-07-01 16:35:55 +04:00
dp - > ihardlimit = qblk - > dqb_ihardlimit ;
dp - > isoftlimit = qblk - > dqb_isoftlimit ;
dp - > curinodes = qblk - > dqb_curinodes ;
dp - > qflags = QUOTAS_ENABLED | QUOTAS_DENY_DISK ;
DEBUG ( 10 , ( " softlimit=%u hardlimit=%u curblock=%u \n " ,
( unsigned ) dp - > softlimit , ( unsigned ) dp - > hardlimit ,
( unsigned ) dp - > curblocks ) ) ;
DEBUGADD ( 10 , ( " softinodes=%u hardinodes=%u curinodes=%u \n " ,
( unsigned ) dp - > isoftlimit , ( unsigned ) dp - > ihardlimit ,
( unsigned ) dp - > curinodes ) ) ;
}
static void xlate_smb_to_qblk ( const SMB_DISK_QUOTA * const dp ,
struct dqblk * qblk )
{
ZERO_STRUCTP ( qblk ) ;
2012-09-02 18:08:58 +04:00
qblk - > dqb_bsoftlimit = dp - > softlimit ;
qblk - > dqb_bhardlimit = dp - > hardlimit ;
# ifdef HAVE_STRUCT_DQBLK_DQB_CURBYTES
2012-07-01 16:35:55 +04:00
/* On Darwin, quotas are counted in bytes. */
2012-09-02 18:08:58 +04:00
qblk - > dqb_bsoftlimit * = dp - > bsize ;
qblk - > dqb_bhardlimit * = dp - > bsize ;
# endif
2012-07-01 16:35:55 +04:00
qblk - > dqb_ihardlimit = dp - > ihardlimit ;
qblk - > dqb_isoftlimit = dp - > isoftlimit ;
}
static int sys_quotactl_4B ( const char * path , int cmd ,
int id , struct dqblk * qblk )
{
int ret ;
/* NB: We must test GRPQUOTA here, because USRQUOTA is 0. */
DEBUG ( 10 , ( " %s quota for %s ID %u on %s \n " ,
( cmd & QCMD ( Q_GETQUOTA , 0 ) ) ? " getting " : " setting " ,
( cmd & QCMD ( 0 , GRPQUOTA ) ) ? " group " : " user " ,
( unsigned ) id , path ) ) ;
# ifdef HFS_QUOTACTL_WAR
become_root ( ) ;
# endif /* HFS_QUOTACTL_WAR */
ret = quotactl ( path , cmd , id , qblk ) ;
if ( ret = = - 1 ) {
/* ENOTSUP means quota support is not compiled in. EINVAL
* means that quotas are not configured ( commonly ) .
*/
if ( errno ! = ENOTSUP & & errno ! = EINVAL ) {
DEBUG ( 0 , ( " failed to %s quota for %s ID %u on %s: %s \n " ,
( cmd & QCMD ( Q_GETQUOTA , 0 ) ) ? " get " : " set " ,
( cmd & QCMD ( 0 , GRPQUOTA ) ) ? " group " : " user " ,
( unsigned ) id , path , strerror ( errno ) ) ) ;
}
# ifdef HFS_QUOTACTL_WAR
unbecome_root ( ) ;
# endif /* HFS_QUOTACTL_WAR */
return - 1 ;
}
# ifdef HFS_QUOTACTL_WAR
unbecome_root ( ) ;
# endif /* HFS_QUOTACTL_WAR */
return 0 ;
}
int sys_get_vfs_quota ( const char * path , const char * bdev ,
enum SMB_QUOTA_TYPE qtype , unid_t id , SMB_DISK_QUOTA * dp )
{
int ret ;
struct dqblk qblk ;
ZERO_STRUCT ( qblk ) ;
switch ( qtype ) {
case SMB_USER_QUOTA_TYPE :
/* Get quota for provided UID. */
ret = sys_quotactl_4B ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) ,
id . uid , & qblk ) ;
break ;
case SMB_USER_FS_QUOTA_TYPE :
/* Get quota for current UID. */
ret = sys_quotactl_4B ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) ,
geteuid ( ) , & qblk ) ;
break ;
case SMB_GROUP_QUOTA_TYPE :
/* Get quota for provided GID. */
ret = sys_quotactl_4B ( path , QCMD ( Q_GETQUOTA , GRPQUOTA ) ,
id . gid , & qblk ) ;
break ;
case SMB_GROUP_FS_QUOTA_TYPE :
/* Get quota for current GID. */
ret = sys_quotactl_4B ( path , QCMD ( Q_GETQUOTA , GRPQUOTA ) ,
getegid ( ) , & qblk ) ;
break ;
default :
DEBUG ( 0 , ( " cannot get unsupported quota type: %u \n " ,
( unsigned ) qtype ) ) ;
errno = ENOSYS ;
return - 1 ;
}
if ( ret = = - 1 ) {
return - 1 ;
}
xlate_qblk_to_smb ( & qblk , dp ) ;
dp - > qtype = qtype ;
return ret ;
}
int sys_set_vfs_quota ( const char * path , const char * bdev ,
enum SMB_QUOTA_TYPE qtype , unid_t id , SMB_DISK_QUOTA * dp )
{
struct dqblk qblk ;
xlate_smb_to_qblk ( dp , & qblk ) ;
switch ( qtype ) {
case SMB_USER_QUOTA_TYPE :
/* Set quota for provided UID. */
return sys_quotactl_4B ( path , QCMD ( Q_SETQUOTA , USRQUOTA ) ,
id . uid , & qblk ) ;
case SMB_USER_FS_QUOTA_TYPE :
/* Set quota for current UID. */
return sys_quotactl_4B ( path , QCMD ( Q_SETQUOTA , USRQUOTA ) ,
geteuid ( ) , & qblk ) ;
case SMB_GROUP_QUOTA_TYPE :
/* Set quota for provided GID. */
return sys_quotactl_4B ( path , QCMD ( Q_SETQUOTA , GRPQUOTA ) ,
id . gid , & qblk ) ;
case SMB_GROUP_FS_QUOTA_TYPE :
/* Set quota for current GID. */
return sys_quotactl_4B ( path , QCMD ( Q_SETQUOTA , GRPQUOTA ) ,
getegid ( ) , & qblk ) ;
default :
DEBUG ( 0 , ( " cannot set unsupported quota type: %u \n " ,
( unsigned ) qtype ) ) ;
errno = ENOSYS ;
return - 1 ;
}
}
# endif /* HAVE_QUOTACTL_4B */