1996-05-05 11:25:33 +00:00
/*
2002-01-30 06:08:46 +00:00
Unix SMB / CIFS implementation .
1996-05-05 11:25:33 +00:00
support for quotas
1998-01-22 13:27:43 +00:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1996-05-05 11:25:33 +00:00
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
2007-07-09 19:25:36 +00:00
the Free Software Foundation ; either version 3 of the License , or
1996-05-05 11:25:33 +00:00
( 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
2007-07-10 00:52:41 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-05-05 11:25:33 +00:00
*/
1996-05-31 15:13:29 +00:00
/*
* This is one of the most system dependent parts of Samba , and its
* done a litle differently . Each system has its own way of doing
* things : - (
*/
# include "includes.h"
2011-03-22 16:57:01 +01:00
# include "smbd/smbd.h"
2011-06-14 08:27:34 +02:00
# include "system/filesys.h"
1996-05-05 11:25:33 +00:00
2004-01-15 08:49:30 +00:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_QUOTA
2003-05-12 01:20:17 +00:00
# ifndef HAVE_SYS_QUOTAS
2003-05-14 14:38:11 +00:00
/* just a quick hack because sysquotas.h is included before linux/quota.h */
# ifdef QUOTABLOCK_SIZE
# undef QUOTABLOCK_SIZE
# endif
2003-05-12 01:20:17 +00:00
# ifdef WITH_QUOTAS
2000-03-13 17:38:13 +00:00
# if defined(VXFS_QUOTA)
/*
* In addition to their native filesystems , some systems have Veritas VxFS .
* Declare here , define at end : reduces likely " include " interaction problems .
* David Lee < T . D . Lee @ durham . ac . uk >
*/
2008-10-14 01:59:36 +02:00
bool disk_quotas_vxfs ( const char * name , char * path , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize ) ;
2000-03-13 17:38:13 +00:00
# endif /* VXFS_QUOTA */
2012-09-02 21:44:54 +02:00
2012-09-03 01:51:59 +10:00
# if defined(SUNOS5) || defined(SUNOS4)
1996-05-05 11:25:33 +00:00
# include <fcntl.h>
1998-11-06 18:40:51 +00:00
# include <sys/param.h>
1996-06-08 04:33:37 +00:00
# if defined(SUNOS5)
1996-05-05 11:25:33 +00:00
# include <sys/fs/ufs_quota.h>
1996-06-08 04:33:37 +00:00
# include <sys/mnttab.h>
2001-02-27 21:46:01 +00:00
# include <sys/mntent.h>
1996-06-08 04:33:37 +00:00
# else /* defined(SUNOS4) */
# include <ufs/quota.h>
# include <mntent.h>
# endif
1996-05-05 11:25:33 +00:00
2001-04-01 19:00:43 +00:00
# if defined(SUNOS5)
/****************************************************************************
Allows querying of remote hosts for quotas on NFS mounted shares .
Supports normal NFS and AMD mounts .
Alan Romeril < a . romeril @ ic . ac . uk > July 2 K .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <rpc/rpc.h>
# include <rpc/types.h>
# include <rpcsvc/rquota.h>
# include <rpc/nettype.h>
# include <rpc/xdr.h>
2005-10-11 14:46:40 +00:00
static int my_xdr_getquota_rslt ( XDR * xdrsp , struct getquota_rslt * gqr )
2001-04-01 19:00:43 +00:00
{
2009-01-08 10:43:10 +01:00
int quotastat ;
2001-04-01 19:00:43 +00:00
if ( ! xdr_int ( xdrsp , & quotastat ) ) {
DEBUG ( 6 , ( " nfs_quotas: Status bad or zero \n " ) ) ;
return 0 ;
}
2009-01-08 10:43:10 +01:00
gqr - > status = quotastat ;
2001-04-05 20:46:15 +00:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsize ) ) {
2001-04-01 19:00:43 +00:00
DEBUG ( 6 , ( " nfs_quotas: Block size bad or zero \n " ) ) ;
return 0 ;
}
if ( ! xdr_bool ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_active ) ) {
DEBUG ( 6 , ( " nfs_quotas: Active bad or zero \n " ) ) ;
return 0 ;
}
2001-04-05 20:46:15 +00:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bhardlimit ) ) {
2001-04-01 19:00:43 +00:00
DEBUG ( 6 , ( " nfs_quotas: Hardlimit bad or zero \n " ) ) ;
return 0 ;
}
2001-04-05 20:46:15 +00:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsoftlimit ) ) {
2001-04-01 19:00:43 +00:00
DEBUG ( 6 , ( " nfs_quotas: Softlimit bad or zero \n " ) ) ;
return 0 ;
}
2001-04-05 20:46:15 +00:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_curblocks ) ) {
2001-04-01 19:00:43 +00:00
DEBUG ( 6 , ( " nfs_quotas: Currentblocks bad or zero \n " ) ) ;
return 0 ;
}
return ( 1 ) ;
}
2012-09-11 01:00:50 +02:00
static int my_xdr_getquota_args ( XDR * xdrsp , struct getquota_args * args )
{
if ( ! xdr_string ( xdrsp , & args - > gqa_pathp , RQ_PATHLEN ) )
return ( 0 ) ;
if ( ! xdr_int ( xdrsp , & args - > gqa_uid ) )
return ( 0 ) ;
return ( 1 ) ;
}
2007-11-13 12:51:31 -08:00
/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
2008-10-14 01:59:36 +02:00
static bool nfs_quotas ( char * nfspath , uid_t euser_id , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
2001-04-01 19:00:43 +00:00
{
uid_t uid = euser_id ;
struct dqblk D ;
char * mnttype = nfspath ;
CLIENT * clnt ;
struct getquota_rslt gqr ;
struct getquota_args args ;
char * cutstr , * pathname , * host , * testpath ;
int len ;
static struct timeval timeout = { 2 , 0 } ;
enum clnt_stat clnt_stat ;
2007-10-18 17:40:25 -07:00
bool ret = True ;
2001-04-27 19:56:15 +00:00
2008-10-14 01:59:36 +02:00
* bsize = * dfree = * dsize = ( uint64_t ) 0 ;
2001-04-01 19:00:43 +00:00
len = strcspn ( mnttype , " : " ) ;
pathname = strstr ( mnttype , " : " ) ;
2004-12-21 01:04:11 +00:00
cutstr = ( char * ) SMB_MALLOC ( len + 1 ) ;
2001-04-01 19:00:43 +00:00
if ( ! cutstr )
return False ;
2003-03-11 18:10:27 +00:00
memset ( cutstr , ' \0 ' , len + 1 ) ;
2001-04-01 19:00:43 +00:00
host = strncat ( cutstr , mnttype , sizeof ( char ) * len ) ;
DEBUG ( 5 , ( " nfs_quotas: looking for mount on \" %s \" \n " , cutstr ) ) ;
DEBUG ( 5 , ( " nfs_quotas: of path \" %s \" \n " , mnttype ) ) ;
2001-07-04 07:36:09 +00:00
testpath = strchr_m ( mnttype , ' : ' ) ;
2001-04-01 19:00:43 +00:00
args . gqa_pathp = testpath + 1 ;
args . gqa_uid = uid ;
DEBUG ( 5 , ( " nfs_quotas: Asking for host \" %s \" rpcprog \" %i \" rpcvers \" %i \" network \" %s \" \n " , host , RQUOTAPROG , RQUOTAVERS , " udp " ) ) ;
2001-04-27 19:56:15 +00:00
if ( ( clnt = clnt_create ( host , RQUOTAPROG , RQUOTAVERS , " udp " ) ) = = NULL ) {
ret = False ;
goto out ;
}
clnt - > cl_auth = authunix_create_default ( ) ;
DEBUG ( 9 , ( " nfs_quotas: auth_success \n " ) ) ;
2001-04-01 19:00:43 +00:00
2005-10-11 14:46:40 +00:00
clnt_stat = clnt_call ( clnt , RQUOTAPROC_GETQUOTA , my_xdr_getquota_args , ( caddr_t ) & args , my_xdr_getquota_rslt , ( caddr_t ) & gqr , timeout ) ;
2001-04-01 19:00:43 +00:00
2001-04-27 19:56:15 +00:00
if ( clnt_stat ! = RPC_SUCCESS ) {
DEBUG ( 9 , ( " nfs_quotas: clnt_call fail \n " ) ) ;
ret = False ;
goto out ;
}
2001-04-01 19:00:43 +00:00
2007-11-13 12:51:31 -08:00
/*
2009-01-08 10:43:10 +01:00
* gqr . status returns 0 if the rpc call fails , 1 if quotas exist , 2 if there is
2001-04-01 19:00:43 +00:00
* no quota set , and 3 if no permission to get the quota . If 0 or 3 return
* something sensible .
2007-11-13 12:51:31 -08:00
*/
2001-04-01 19:00:43 +00:00
2009-01-08 10:43:10 +01:00
switch ( gqr . status ) {
2001-04-27 19:56:15 +00:00
case 0 :
2009-01-08 10:43:10 +01:00
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Failed! Error \" %i \" \n " , gqr . status ) ) ;
2001-04-27 19:56:15 +00:00
ret = False ;
goto out ;
case 1 :
2001-04-01 19:00:43 +00:00
DEBUG ( 9 , ( " nfs_quotas: Good quota data \n " ) ) ;
D . dqb_bsoftlimit = gqr . getquota_rslt_u . gqr_rquota . rq_bsoftlimit ;
D . dqb_bhardlimit = gqr . getquota_rslt_u . gqr_rquota . rq_bhardlimit ;
D . dqb_curblocks = gqr . getquota_rslt_u . gqr_rquota . rq_curblocks ;
2001-04-27 19:56:15 +00:00
break ;
2001-04-01 19:00:43 +00:00
2001-04-27 19:56:15 +00:00
case 2 :
case 3 :
2001-04-01 19:00:43 +00:00
D . dqb_bsoftlimit = 1 ;
D . dqb_curblocks = 1 ;
2009-01-08 10:43:10 +01:00
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas returned \" %i \" \n " , gqr . status ) ) ;
2001-04-27 19:56:15 +00:00
break ;
2001-04-01 19:00:43 +00:00
2001-04-27 19:56:15 +00:00
default :
2009-01-08 10:43:10 +01:00
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Questionable! Error \" %i \" \n " , gqr . status ) ) ;
2001-04-27 19:56:15 +00:00
break ;
}
2001-04-01 19:00:43 +00:00
DEBUG ( 10 , ( " nfs_quotas: Let`s look at D a bit closer... status \" %i \" bsize \" %i \" active? \" %i \" bhard \" %i \" bsoft \" %i \" curb \" %i \" \n " ,
2009-01-08 10:43:10 +01:00
gqr . status ,
2001-04-01 19:00:43 +00:00
gqr . getquota_rslt_u . gqr_rquota . rq_bsize ,
gqr . getquota_rslt_u . gqr_rquota . rq_active ,
gqr . getquota_rslt_u . gqr_rquota . rq_bhardlimit ,
gqr . getquota_rslt_u . gqr_rquota . rq_bsoftlimit ,
gqr . getquota_rslt_u . gqr_rquota . rq_curblocks ) ) ;
* bsize = gqr . getquota_rslt_u . gqr_rquota . rq_bsize ;
* dsize = D . dqb_bsoftlimit ;
if ( D . dqb_curblocks > D . dqb_bsoftlimit ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
} else
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
2001-04-27 19:56:15 +00:00
out :
if ( clnt ) {
if ( clnt - > cl_auth )
auth_destroy ( clnt - > cl_auth ) ;
clnt_destroy ( clnt ) ;
}
2001-04-01 19:00:43 +00:00
DEBUG ( 5 , ( " nfs_quotas: For path \" %s \" returning bsize %.0f, dfree %.0f, dsize %.0f \n " , args . gqa_pathp , ( double ) * bsize , ( double ) * dfree , ( double ) * dsize ) ) ;
2001-09-17 11:25:41 +00:00
SAFE_FREE ( cutstr ) ;
2001-04-01 19:00:43 +00:00
DEBUG ( 10 , ( " nfs_quotas: End of nfs_quotas \n " ) ) ;
2001-04-27 19:56:15 +00:00
return ret ;
2001-04-01 19:00:43 +00:00
}
# endif
1996-05-05 11:25:33 +00:00
/****************************************************************************
1998-11-06 18:40:51 +00:00
try to get the disk space from disk quotas ( SunOS & Solaris2 version )
1998-11-09 20:33:37 +00:00
Quota code by Peter Urbanec ( amiga @ cse . unsw . edu . au ) .
1998-11-06 18:40:51 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-13 12:51:31 -08:00
bool disk_quotas ( const char * path ,
2008-10-14 01:59:36 +02:00
uint64_t * bsize ,
uint64_t * dfree ,
uint64_t * dsize )
1996-05-05 11:25:33 +00:00
{
2001-04-01 19:00:43 +00:00
uid_t euser_id ;
int ret ;
struct dqblk D ;
1996-06-08 04:33:37 +00:00
# if defined(SUNOS5)
2001-04-01 19:00:43 +00:00
struct quotctl command ;
int file ;
2007-11-13 12:51:31 -08:00
struct mnttab mnt ;
1998-11-06 18:40:51 +00:00
# else /* SunOS4 */
2001-04-01 19:00:43 +00:00
struct mntent * mnt ;
1996-06-08 04:33:37 +00:00
# endif
2007-11-13 12:51:31 -08:00
char * name = NULL ;
2001-04-01 19:00:43 +00:00
FILE * fd ;
SMB_STRUCT_STAT sbuf ;
2007-11-13 12:51:31 -08:00
SMB_DEV_T devno ;
bool found = false ;
1999-12-13 13:27:58 +00:00
2001-04-01 19:00:43 +00:00
euser_id = geteuid ( ) ;
2007-11-13 12:51:31 -08:00
2009-12-12 16:58:31 +01:00
if ( sys_stat ( path , & sbuf , false ) = = - 1 ) {
2007-11-13 12:51:31 -08:00
return false ;
}
2009-06-29 16:26:42 +02:00
devno = sbuf . st_ex_dev ;
2006-10-13 05:22:36 +00:00
DEBUG ( 5 , ( " disk_quotas: looking for path \" %s \" devno=%x \n " ,
path , ( unsigned int ) devno ) ) ;
1996-06-08 04:33:37 +00:00
# if defined(SUNOS5)
2012-03-28 12:51:17 +11:00
if ( ( fd = fopen ( MNTTAB , " r " ) ) = = NULL ) {
2007-11-13 12:51:31 -08:00
return false ;
}
while ( getmntent ( fd , & mnt ) = = 0 ) {
2009-11-27 12:57:43 +01:00
if ( sys_stat ( mnt . mnt_mountp , & sbuf , false ) = = - 1 ) {
2007-11-13 12:51:31 -08:00
continue ;
2001-04-01 19:00:43 +00:00
}
2007-11-13 12:51:31 -08:00
DEBUG ( 5 , ( " disk_quotas: testing \" %s \" devno=%x \n " ,
mnt . mnt_mountp , ( unsigned int ) devno ) ) ;
/* quotas are only on vxfs, UFS or NFS */
2009-06-29 16:26:42 +02:00
if ( ( sbuf . st_ex_dev = = devno ) & & (
2007-11-13 12:51:31 -08:00
strcmp ( mnt . mnt_fstype , MNTTYPE_UFS ) = = 0 | |
strcmp ( mnt . mnt_fstype , " nfs " ) = = 0 | |
strcmp ( mnt . mnt_fstype , " vxfs " ) = = 0 ) ) {
found = true ;
name = talloc_asprintf ( talloc_tos ( ) ,
" %s/quotas " ,
mnt . mnt_mountp ) ;
2001-04-01 19:00:43 +00:00
break ;
}
}
1996-05-05 11:25:33 +00:00
2007-11-13 12:51:31 -08:00
fclose ( fd ) ;
# else /* SunOS4 */
if ( ( fd = setmntent ( MOUNTED , " r " ) ) = = NULL ) {
return false ;
}
while ( ( mnt = getmntent ( fd ) ) ! = NULL ) {
2009-11-27 12:57:43 +01:00
if ( sys_stat ( mnt - > mnt_dir , & sbuf , false ) = = - 1 ) {
2007-11-13 12:51:31 -08:00
continue ;
}
DEBUG ( 5 , ( " disk_quotas: testing \" %s \" devno=%x \n " ,
mnt - > mnt_dir ,
2009-06-29 16:26:42 +02:00
( unsigned int ) sbuf . st_ex_dev ) ) ;
if ( sbuf . st_ex_dev = = devno ) {
2007-11-13 12:51:31 -08:00
found = true ;
name = talloc_strdup ( talloc_tos ( ) ,
mnt - > mnt_fsname ) ;
break ;
}
}
2001-02-27 21:46:01 +00:00
2007-11-13 12:51:31 -08:00
endmntent ( fd ) ;
# endif
if ( ! found ) {
return false ;
}
if ( ! name ) {
return false ;
}
2007-04-05 23:56:10 +00:00
become_root ( ) ;
1996-05-31 15:13:29 +00:00
1996-06-08 04:33:37 +00:00
# if defined(SUNOS5)
2007-11-13 12:51:31 -08:00
if ( strcmp ( mnt . mnt_fstype , " nfs " ) = = 0 ) {
2007-10-18 17:40:25 -07:00
bool retval ;
2007-11-13 12:51:31 -08:00
DEBUG ( 5 , ( " disk_quotas: looking for mountpath (NFS) \" %s \" \n " ,
mnt . mnt_special ) ) ;
retval = nfs_quotas ( mnt . mnt_special ,
euser_id , bsize , dfree , dsize ) ;
2007-04-10 15:41:23 +00:00
unbecome_root ( ) ;
2001-04-01 19:00:43 +00:00
return retval ;
}
DEBUG ( 5 , ( " disk_quotas: looking for quotas file \" %s \" \n " , name ) ) ;
2012-03-28 12:48:00 +11:00
if ( ( file = open ( name , O_RDONLY , 0 ) ) < 0 ) {
2007-04-05 23:56:10 +00:00
unbecome_root ( ) ;
2007-11-13 12:51:31 -08:00
return false ;
2001-04-01 19:00:43 +00:00
}
command . op = Q_GETQUOTA ;
command . uid = euser_id ;
command . addr = ( caddr_t ) & D ;
ret = ioctl ( file , Q_QUOTACTL , & command ) ;
close ( file ) ;
1996-06-08 04:33:37 +00:00
# else
2001-04-01 19:00:43 +00:00
DEBUG ( 5 , ( " disk_quotas: trying quotactl on device \" %s \" \n " , name ) ) ;
ret = quotactl ( Q_GETQUOTA , name , euser_id , & D ) ;
1996-06-08 04:33:37 +00:00
# endif
1996-05-05 11:25:33 +00:00
2007-04-05 23:56:10 +00:00
unbecome_root ( ) ;
1996-05-05 11:25:33 +00:00
2001-04-01 19:00:43 +00:00
if ( ret < 0 ) {
2007-11-13 12:51:31 -08:00
DEBUG ( 5 , ( " disk_quotas ioctl (Solaris) failed. Error = %s \n " ,
strerror ( errno ) ) ) ;
2000-03-13 17:38:13 +00:00
# if defined(SUNOS5) && defined(VXFS_QUOTA)
2001-04-01 19:00:43 +00:00
/* If normal quotactl() fails, try vxfs private calls */
set_effective_uid ( euser_id ) ;
DEBUG ( 5 , ( " disk_quotas: mount type \" %s \" \n " , mnt . mnt_fstype ) ) ;
if ( 0 = = strcmp ( mnt . mnt_fstype , " vxfs " ) ) {
2007-10-18 17:40:25 -07:00
bool retval ;
2007-11-13 12:51:31 -08:00
retval = disk_quotas_vxfs ( name , path ,
bsize , dfree , dsize ) ;
return retval ;
2001-04-01 19:00:43 +00:00
}
2000-03-13 17:38:13 +00:00
# else
2007-11-13 12:51:31 -08:00
return false ;
2000-03-13 17:38:13 +00:00
# endif
2001-04-01 19:00:43 +00:00
}
1996-05-31 15:13:29 +00:00
2001-04-01 19:00:43 +00:00
/* If softlimit is zero, set it equal to hardlimit.
*/
2007-11-13 12:51:31 -08:00
if ( D . dqb_bsoftlimit = = 0 ) {
2001-04-01 19:00:43 +00:00
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
2007-11-13 12:51:31 -08:00
}
2001-04-01 19:00:43 +00:00
2007-11-13 12:51:31 -08:00
/* Use softlimit to determine disk space. A user exceeding the quota
* is told that there ' s no space left . Writes might actually work for
* a bit if the hardlimit is set higher than softlimit . Effectively
* the disk becomes made of rubber latex and begins to expand to
* accommodate the user : - )
2001-04-01 19:00:43 +00:00
*/
if ( D . dqb_bsoftlimit = = 0 )
return ( False ) ;
* bsize = DEV_BSIZE ;
* dsize = D . dqb_bsoftlimit ;
if ( D . dqb_curblocks > D . dqb_bsoftlimit ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
2007-11-13 12:51:31 -08:00
} else {
2001-04-01 19:00:43 +00:00
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
2007-11-13 12:51:31 -08:00
}
DEBUG ( 5 , ( " disk_quotas for path \" %s \" returning "
" bsize %.0f, dfree %.0f, dsize %.0f \n " ,
2001-04-01 19:00:43 +00:00
path , ( double ) * bsize , ( double ) * dfree , ( double ) * dsize ) ) ;
1996-05-05 11:25:33 +00:00
2007-11-13 12:51:31 -08:00
return true ;
1996-05-05 11:25:33 +00:00
}
1997-08-19 19:22:26 +00:00
1996-05-05 11:25:33 +00:00
# else
2012-09-03 01:51:59 +10:00
# if AIX
1997-07-08 16:54:44 +00:00
/* AIX quota patch from Ole Holm Nielsen <ohnielse@fysik.dtu.dk> */
# include <jfs/quota.h>
/* AIX 4.X: Rename members of the dqblk structure (ohnielse@fysik.dtu.dk) */
# define dqb_curfiles dqb_curinodes
# define dqb_fhardlimit dqb_ihardlimit
# define dqb_fsoftlimit dqb_isoftlimit
2007-04-03 17:10:52 +00:00
# ifdef _AIXVERSION_530
# include <sys/statfs.h>
# include <sys/vmount.h>
# endif /* AIX 5.3 */
2012-09-03 13:16:38 +10:00
# else /* !AIX */
1996-05-31 15:13:29 +00:00
# include <sys/quota.h>
# include <devnm.h>
1996-12-10 17:58:11 +00:00
# endif
1996-05-31 15:13:29 +00:00
2004-07-03 23:53:36 +00:00
1996-05-05 11:25:33 +00:00
/****************************************************************************
try to get the disk space from disk quotas - default version
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-06 18:40:51 +00:00
2008-10-14 01:59:36 +02:00
bool disk_quotas ( const char * path , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
1996-05-05 11:25:33 +00:00
{
int r ;
struct dqblk D ;
1999-12-13 13:27:58 +00:00
uid_t euser_id ;
2012-09-03 13:16:38 +10:00
# if !defined(AIX)
1997-07-02 01:19:41 +00:00
char dev_disk [ 256 ] ;
1998-09-01 20:11:54 +00:00
SMB_STRUCT_STAT S ;
2003-01-28 02:15:11 +00:00
1996-05-05 11:25:33 +00:00
/* find the block device file */
2003-01-28 02:15:11 +00:00
2009-11-27 12:57:43 +01:00
if ( ( sys_stat ( path , & S , false ) < 0 )
2009-11-27 12:42:39 +01:00
| | ( devnm ( S_IFBLK , S . st_ex_dev , dev_disk , 256 , 0 ) < 0 ) )
2003-05-01 11:02:54 +00:00
return ( False ) ;
2003-01-28 02:15:11 +00:00
2012-09-03 13:16:38 +10:00
# endif /* !defined(AIX) */
1996-05-05 11:25:33 +00:00
euser_id = geteuid ( ) ;
2012-09-03 01:51:59 +10:00
# if defined(AIX)
1997-07-08 16:54:44 +00:00
/* AIX has both USER and GROUP quotas:
Get the USER quota ( ohnielse @ fysik . dtu . dk ) */
2007-04-03 17:10:52 +00:00
# ifdef _AIXVERSION_530
{
struct statfs statbuf ;
quota64_t user_quota ;
if ( statfs ( path , & statbuf ) ! = 0 )
return False ;
if ( statbuf . f_vfstype = = MNT_J2 )
{
/* For some reason we need to be root for jfs2 */
2007-04-05 23:56:10 +00:00
become_root ( ) ;
2007-04-03 17:10:52 +00:00
r = quotactl ( path , QCMD ( Q_J2GETQUOTA , USRQUOTA ) , euser_id , ( char * ) & user_quota ) ;
2007-04-05 23:56:10 +00:00
unbecome_root ( ) ;
2007-04-03 17:10:52 +00:00
/* Copy results to old struct to let the following code work as before */
D . dqb_curblocks = user_quota . bused ;
D . dqb_bsoftlimit = user_quota . bsoft ;
D . dqb_bhardlimit = user_quota . bhard ;
2007-09-24 21:43:54 +00:00
D . dqb_curfiles = user_quota . iused ;
D . dqb_fsoftlimit = user_quota . isoft ;
D . dqb_fhardlimit = user_quota . ihard ;
2007-04-03 17:10:52 +00:00
}
else if ( statbuf . f_vfstype = = MNT_JFS )
{
# endif /* AIX 5.3 */
2004-03-16 19:06:03 +00:00
save_re_uid ( ) ;
if ( set_re_uid ( ) ! = 0 )
return False ;
1997-07-08 16:54:44 +00:00
r = quotactl ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) , euser_id , ( char * ) & D ) ;
2004-03-16 19:06:03 +00:00
restore_re_uid ( ) ;
2007-04-03 17:10:52 +00:00
# ifdef _AIXVERSION_530
}
else
r = 1 ; /* Fail for other FS-types */
}
# endif /* AIX 5.3 */
2012-09-03 13:16:38 +10:00
# else /* !AIX */
1996-12-10 17:58:11 +00:00
r = quotactl ( Q_GETQUOTA , dev_disk , euser_id , & D ) ;
2012-09-03 13:16:38 +10:00
# endif /* !AIX */
1996-12-10 17:58:11 +00:00
1996-05-05 11:25:33 +00:00
/* Use softlimit to determine disk space, except when it has been exceeded */
* bsize = 1024 ;
1997-10-08 20:34:13 +00:00
1996-05-05 11:25:33 +00:00
if ( r )
{
if ( errno = = EDQUOT )
{
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
return ( True ) ;
}
else return ( False ) ;
}
2000-04-10 21:02:45 +00:00
/* If softlimit is zero, set it equal to hardlimit.
*/
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
1996-06-08 04:33:37 +00:00
if ( D . dqb_bsoftlimit = = 0 )
return ( False ) ;
1996-05-05 11:25:33 +00:00
/* Use softlimit to determine disk space, except when it has been exceeded */
1996-12-10 17:58:11 +00:00
if ( ( D . dqb_curblocks > D . dqb_bsoftlimit )
1997-07-17 20:11:58 +00:00
| | ( ( D . dqb_curfiles > D . dqb_fsoftlimit ) & & ( D . dqb_fsoftlimit ! = 0 ) )
1996-12-10 17:58:11 +00:00
) {
1996-05-05 11:25:33 +00:00
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
}
else {
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
* dsize = D . dqb_bsoftlimit ;
}
return ( True ) ;
}
# endif
2000-03-13 17:38:13 +00:00
# if defined(VXFS_QUOTA)
/****************************************************************************
Try to get the disk space from Veritas disk quotas .
David Lee < T . D . Lee @ durham . ac . uk > August 1999.
Background assumptions :
Potentially under many Operating Systems . Initially Solaris 2.
My guess is that Veritas is largely , though not entirely ,
independent of OS . So I have separated it out .
There may be some details . For example , OS - specific " include " files .
It is understood that HPUX 10 somehow gets Veritas quotas without
any special effort ; if so , this routine need not be compiled in .
Dirk De Wachter < Dirk . DeWachter @ rug . ac . be >
Warning :
It is understood that Veritas do not publicly support this ioctl interface .
Rather their preference would be for the user ( us ) to call the native
OS and then for the OS itself to call through to the VxFS filesystem .
Presumably HPUX 10 , see above , does this .
Hints for porting :
Add your OS to " IFLIST " below .
Get it to compile successfully :
Almost certainly " include " s require attention : see SUNOS5 .
In the main code above , arrange for it to be called : see SUNOS5 .
Test !
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* "IFLIST"
* This " if " is a list of ports :
* if defined ( OS1 ) | | defined ( OS2 ) | | . . .
*/
# if defined(SUNOS5)
# if defined(SUNOS5)
# include <sys/fs/vx_solaris.h>
# endif
# include <sys/fs/vx_machdep.h>
# include <sys/fs/vx_layout.h>
# include <sys/fs/vx_quota.h>
# include <sys/fs/vx_aioctl.h>
# include <sys/fs/vx_ioctl.h>
2008-10-14 01:59:36 +02:00
bool disk_quotas_vxfs ( const char * name , char * path , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
2000-03-13 17:38:13 +00:00
{
uid_t user_id , euser_id ;
int ret ;
struct vx_dqblk D ;
struct vx_quotctl quotabuf ;
struct vx_genioctl genbuf ;
2007-11-13 12:51:31 -08:00
char * qfname ;
2000-03-13 17:38:13 +00:00
int file ;
/*
* " name " may or may not include a trailing " /quotas " .
* Arranging consistency of calling here in " quotas.c " may not be easy and
* it might be easier to examine and adjust it here .
* Fortunately , VxFS seems not to mind at present .
*/
2007-11-13 12:51:31 -08:00
qfname = talloc_strdup ( talloc_tos ( ) , name ) ;
if ( ! qfname ) {
return false ;
}
2000-03-13 17:38:13 +00:00
/* pstrcat(qfname, "/quotas") ; */ /* possibly examine and adjust "name" */
euser_id = geteuid ( ) ;
set_effective_uid ( 0 ) ;
DEBUG ( 5 , ( " disk_quotas: looking for VxFS quotas file \" %s \" \n " , qfname ) ) ;
2012-03-28 12:48:00 +11:00
if ( ( file = open ( qfname , O_RDONLY , 0 ) ) < 0 ) {
2000-03-13 17:38:13 +00:00
set_effective_uid ( euser_id ) ;
return ( False ) ;
}
genbuf . ioc_cmd = VX_QUOTACTL ;
genbuf . ioc_up = ( void * ) & quotabuf ;
quotabuf . cmd = VX_GETQUOTA ;
quotabuf . uid = euser_id ;
quotabuf . addr = ( caddr_t ) & D ;
ret = ioctl ( file , VX_ADMIN_IOCTL , & genbuf ) ;
close ( file ) ;
set_effective_uid ( euser_id ) ;
if ( ret < 0 ) {
DEBUG ( 5 , ( " disk_quotas ioctl (VxFS) failed. Error = %s \n " , strerror ( errno ) ) ) ;
return ( False ) ;
}
2000-04-10 21:02:45 +00:00
/* If softlimit is zero, set it equal to hardlimit.
*/
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
2000-03-13 17:38:13 +00:00
/* Use softlimit to determine disk space. A user exceeding the quota is told
* that there ' s no space left . Writes might actually work for a bit if the
* hardlimit is set higher than softlimit . Effectively the disk becomes
* made of rubber latex and begins to expand to accommodate the user : - )
*/
DEBUG ( 5 , ( " disk_quotas for path \" %s \" block c/s/h %ld/%ld/%ld; file c/s/h %ld/%ld/%ld \n " ,
path , D . dqb_curblocks , D . dqb_bsoftlimit , D . dqb_bhardlimit ,
D . dqb_curfiles , D . dqb_fsoftlimit , D . dqb_fhardlimit ) ) ;
if ( D . dqb_bsoftlimit = = 0 )
return ( False ) ;
* bsize = DEV_BSIZE ;
* dsize = D . dqb_bsoftlimit ;
if ( D . dqb_curblocks > D . dqb_bsoftlimit ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
} else
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
DEBUG ( 5 , ( " disk_quotas for path \" %s \" returning bsize %.0f, dfree %.0f, dsize %.0f \n " ,
path , ( double ) * bsize , ( double ) * dfree , ( double ) * dsize ) ) ;
return ( True ) ;
}
# endif /* SUNOS5 || ... */
# endif /* VXFS_QUOTA */
2003-05-12 01:20:17 +00:00
# else /* WITH_QUOTAS */
2008-10-14 01:59:36 +02:00
bool disk_quotas ( const char * path , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
2003-05-12 01:20:17 +00:00
{
2007-11-13 12:51:31 -08:00
( * bsize ) = 512 ; /* This value should be ignored */
2003-05-12 01:20:17 +00:00
2007-11-13 12:51:31 -08:00
/* And just to be sure we set some values that hopefully */
/* will be larger that any possible real-world value */
2008-10-14 01:59:36 +02:00
( * dfree ) = ( uint64_t ) - 1 ;
( * dsize ) = ( uint64_t ) - 1 ;
2003-05-12 01:20:17 +00:00
2007-11-13 12:51:31 -08:00
/* As we have select not to use quotas, allways fail */
return false ;
2003-05-12 01:20:17 +00:00
}
# endif /* WITH_QUOTAS */
# else /* HAVE_SYS_QUOTAS */
2007-11-13 12:51:31 -08:00
/* wrapper to the new sys_quota interface
2003-05-12 01:20:17 +00:00
this file should be removed later
*/
2008-10-14 01:59:36 +02:00
bool disk_quotas ( const char * path , uint64_t * bsize , uint64_t * dfree , uint64_t * dsize )
2003-05-12 01:20:17 +00:00
{
int r ;
SMB_DISK_QUOTA D ;
unid_t id ;
id . uid = geteuid ( ) ;
2004-01-15 08:49:30 +00:00
ZERO_STRUCT ( D ) ;
2003-05-12 01:20:17 +00:00
r = sys_get_quota ( path , SMB_USER_QUOTA_TYPE , id , & D ) ;
/* Use softlimit to determine disk space, except when it has been exceeded */
* bsize = D . bsize ;
if ( r = = - 1 ) {
if ( errno = = EDQUOT ) {
* dfree = 0 ;
* dsize = D . curblocks ;
return ( True ) ;
} else {
goto try_group_quota ;
}
}
/* Use softlimit to determine disk space, except when it has been exceeded */
if (
( D . softlimit & & D . curblocks > = D . softlimit ) | |
( D . hardlimit & & D . curblocks > = D . hardlimit ) | |
( D . isoftlimit & & D . curinodes > = D . isoftlimit ) | |
( D . ihardlimit & & D . curinodes > = D . ihardlimit )
) {
* dfree = 0 ;
* dsize = D . curblocks ;
} else if ( D . softlimit = = 0 & & D . hardlimit = = 0 ) {
goto try_group_quota ;
} else {
if ( D . softlimit = = 0 )
D . softlimit = D . hardlimit ;
* dfree = D . softlimit - D . curblocks ;
* dsize = D . softlimit ;
}
return True ;
try_group_quota :
id . gid = getegid ( ) ;
2004-01-15 08:49:30 +00:00
ZERO_STRUCT ( D ) ;
2003-05-12 01:20:17 +00:00
r = sys_get_quota ( path , SMB_GROUP_QUOTA_TYPE , id , & D ) ;
/* Use softlimit to determine disk space, except when it has been exceeded */
* bsize = D . bsize ;
if ( r = = - 1 ) {
if ( errno = = EDQUOT ) {
* dfree = 0 ;
* dsize = D . curblocks ;
return ( True ) ;
} else {
return False ;
}
}
/* Use softlimit to determine disk space, except when it has been exceeded */
if (
( D . softlimit & & D . curblocks > = D . softlimit ) | |
( D . hardlimit & & D . curblocks > = D . hardlimit ) | |
( D . isoftlimit & & D . curinodes > = D . isoftlimit ) | |
( D . ihardlimit & & D . curinodes > = D . ihardlimit )
) {
* dfree = 0 ;
* dsize = D . curblocks ;
} else if ( D . softlimit = = 0 & & D . hardlimit = = 0 ) {
return False ;
} else {
if ( D . softlimit = = 0 )
D . softlimit = D . hardlimit ;
* dfree = D . softlimit - D . curblocks ;
* dsize = D . softlimit ;
}
return ( True ) ;
}
# endif /* HAVE_SYS_QUOTAS */