1996-05-05 15:25:33 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-05 15:25:33 +04:00
support for quotas
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
1996-05-05 15:25:33 +04: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
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 .
*/
1996-05-31 19:13:29 +04: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"
1996-05-05 15:25:33 +04:00
2004-01-15 11:49:30 +03:00
# undef DBGC_CLASS
# define DBGC_CLASS DBGC_QUOTA
2003-05-12 05:20:17 +04:00
# ifndef HAVE_SYS_QUOTAS
2003-05-14 18:38:11 +04:00
/* just a quick hack because sysquotas.h is included before linux/quota.h */
# ifdef QUOTABLOCK_SIZE
# undef QUOTABLOCK_SIZE
# endif
2003-05-12 05:20:17 +04:00
# ifdef WITH_QUOTAS
2000-03-13 20:38:13 +03: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 >
*/
BOOL disk_quotas_vxfs ( const pstring name , char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize ) ;
# endif /* VXFS_QUOTA */
1996-05-05 15:25:33 +04:00
# ifdef LINUX
1996-05-31 19:13:29 +04:00
1997-06-11 05:03:06 +04:00
# include <sys/types.h>
2004-01-05 22:36:02 +03:00
# include <mntent.h>
2001-09-22 02:06:03 +04:00
/*
* This shouldn ' t be neccessary - it should be / usr / include / sys / quota . h
2004-01-05 22:36:02 +03:00
* So we include all the files has * should * be in the system into a large ,
* grungy samba_linux_quoatas . h Sometimes I * hate * Linux : - ) . JRA .
2001-09-22 02:06:03 +04:00
*/
2004-01-05 22:36:02 +03:00
# include "samba_linux_quota.h"
# include "samba_xfs_quota.h"
2001-09-22 02:06:03 +04:00
typedef struct _LINUX_SMB_DISK_QUOTA {
SMB_BIG_UINT bsize ;
SMB_BIG_UINT hardlimit ; /* In bsize units. */
SMB_BIG_UINT softlimit ; /* In bsize units. */
SMB_BIG_UINT curblocks ; /* In bsize units. */
SMB_BIG_UINT ihardlimit ; /* inode hard limit. */
SMB_BIG_UINT isoftlimit ; /* inode soft limit. */
SMB_BIG_UINT curinodes ; /* Current used inodes. */
} LINUX_SMB_DISK_QUOTA ;
2001-12-01 00:50:02 +03:00
/****************************************************************************
Abstract out the XFS Quota Manager quota get call .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-01-05 22:36:02 +03:00
static int get_smb_linux_xfs_quota ( char * path , uid_t euser_id , gid_t egrp_id , LINUX_SMB_DISK_QUOTA * dp )
2001-12-01 00:50:02 +03:00
{
2003-11-19 05:19:34 +03:00
struct fs_disk_quota D ;
2004-01-05 22:36:02 +03:00
int ret ;
2003-11-19 05:19:34 +03:00
ZERO_STRUCT ( D ) ;
2004-01-15 11:49:30 +03:00
ret = quotactl ( QCMD ( Q_XGETQUOTA , USRQUOTA ) , path , euser_id , ( caddr_t ) & D ) ;
2003-11-19 05:19:34 +03:00
2004-01-05 22:36:02 +03:00
if ( ret )
2004-01-15 11:49:30 +03:00
ret = quotactl ( QCMD ( Q_XGETQUOTA , GRPQUOTA ) , path , egrp_id , ( caddr_t ) & D ) ;
2004-01-05 22:36:02 +03:00
if ( ret )
return ret ;
2003-11-19 05:19:34 +03:00
dp - > bsize = ( SMB_BIG_UINT ) 512 ;
dp - > softlimit = ( SMB_BIG_UINT ) D . d_blk_softlimit ;
dp - > hardlimit = ( SMB_BIG_UINT ) D . d_blk_hardlimit ;
dp - > ihardlimit = ( SMB_BIG_UINT ) D . d_ino_hardlimit ;
dp - > isoftlimit = ( SMB_BIG_UINT ) D . d_ino_softlimit ;
dp - > curinodes = ( SMB_BIG_UINT ) D . d_icount ;
dp - > curblocks = ( SMB_BIG_UINT ) D . d_bcount ;
2004-01-05 22:36:02 +03:00
2003-11-19 05:19:34 +03:00
return ret ;
2001-12-01 00:50:02 +03:00
}
2001-09-22 02:06:03 +04:00
/****************************************************************************
Abstract out the old and new Linux quota get calls .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-01-05 22:36:02 +03:00
static int get_smb_linux_v1_quota ( char * path , uid_t euser_id , gid_t egrp_id , LINUX_SMB_DISK_QUOTA * dp )
2001-09-22 02:06:03 +04:00
{
2004-01-05 22:36:02 +03:00
struct v1_kern_dqblk D ;
int ret ;
2001-09-22 02:06:03 +04:00
ZERO_STRUCT ( D ) ;
2004-01-05 22:36:02 +03:00
ret = quotactl ( QCMD ( Q_V1_GETQUOTA , USRQUOTA ) , path , euser_id , ( caddr_t ) & D ) ;
if ( ret & & errno ! = EDQUOT )
ret = quotactl ( QCMD ( Q_V1_GETQUOTA , GRPQUOTA ) , path , egrp_id , ( caddr_t ) & D ) ;
if ( ret & & errno ! = EDQUOT )
return ret ;
dp - > bsize = ( SMB_BIG_UINT ) QUOTABLOCK_SIZE ;
dp - > softlimit = ( SMB_BIG_UINT ) D . dqb_bsoftlimit ;
dp - > hardlimit = ( SMB_BIG_UINT ) D . dqb_bhardlimit ;
dp - > ihardlimit = ( SMB_BIG_UINT ) D . dqb_ihardlimit ;
dp - > isoftlimit = ( SMB_BIG_UINT ) D . dqb_isoftlimit ;
dp - > curinodes = ( SMB_BIG_UINT ) D . dqb_curinodes ;
dp - > curblocks = ( SMB_BIG_UINT ) D . dqb_curblocks ;
return ret ;
}
static int get_smb_linux_v2_quota ( char * path , uid_t euser_id , gid_t egrp_id , LINUX_SMB_DISK_QUOTA * dp )
{
struct v2_kern_dqblk D ;
int ret ;
2001-09-22 02:06:03 +04:00
ZERO_STRUCT ( D ) ;
2004-01-05 22:36:02 +03:00
ret = quotactl ( QCMD ( Q_V2_GETQUOTA , USRQUOTA ) , path , euser_id , ( caddr_t ) & D ) ;
if ( ret & & errno ! = EDQUOT )
ret = quotactl ( QCMD ( Q_V2_GETQUOTA , GRPQUOTA ) , path , egrp_id , ( caddr_t ) & D ) ;
if ( ret & & errno ! = EDQUOT )
return ret ;
2001-09-22 02:06:03 +04:00
dp - > bsize = ( SMB_BIG_UINT ) QUOTABLOCK_SIZE ;
2004-01-05 22:36:02 +03:00
dp - > softlimit = ( SMB_BIG_UINT ) D . dqb_bsoftlimit ;
dp - > hardlimit = ( SMB_BIG_UINT ) D . dqb_bhardlimit ;
dp - > ihardlimit = ( SMB_BIG_UINT ) D . dqb_ihardlimit ;
dp - > isoftlimit = ( SMB_BIG_UINT ) D . dqb_isoftlimit ;
dp - > curinodes = ( SMB_BIG_UINT ) D . dqb_curinodes ;
dp - > curblocks = ( ( SMB_BIG_UINT ) D . dqb_curspace ) / dp - > bsize ;
return ret ;
}
/****************************************************************************
Brand - new generic quota interface .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_smb_linux_gen_quota ( char * path , uid_t euser_id , gid_t egrp_id , LINUX_SMB_DISK_QUOTA * dp )
{
struct if_dqblk D ;
int ret ;
ZERO_STRUCT ( D ) ;
2001-09-22 02:06:03 +04:00
2003-11-19 05:19:34 +03:00
ret = quotactl ( QCMD ( Q_GETQUOTA , USRQUOTA ) , path , euser_id , ( caddr_t ) & D ) ;
2004-01-05 22:36:02 +03:00
if ( ret & & errno ! = EDQUOT )
ret = quotactl ( QCMD ( Q_GETQUOTA , GRPQUOTA ) , path , egrp_id , ( caddr_t ) & D ) ;
2001-09-22 02:06:03 +04:00
2004-01-05 22:36:02 +03:00
if ( ret & & errno ! = EDQUOT )
return ret ;
dp - > bsize = ( SMB_BIG_UINT ) QUOTABLOCK_SIZE ;
2001-09-22 02:06:03 +04:00
dp - > softlimit = ( SMB_BIG_UINT ) D . dqb_bsoftlimit ;
dp - > hardlimit = ( SMB_BIG_UINT ) D . dqb_bhardlimit ;
dp - > ihardlimit = ( SMB_BIG_UINT ) D . dqb_ihardlimit ;
dp - > isoftlimit = ( SMB_BIG_UINT ) D . dqb_isoftlimit ;
dp - > curinodes = ( SMB_BIG_UINT ) D . dqb_curinodes ;
2004-01-05 22:36:02 +03:00
dp - > curblocks = ( ( SMB_BIG_UINT ) D . dqb_curspace ) / dp - > bsize ;
2001-09-22 02:06:03 +04:00
2003-11-19 05:19:34 +03:00
return ret ;
2001-09-22 02:06:03 +04:00
}
1996-05-31 19:13:29 +04:00
1996-05-05 15:25:33 +04:00
/****************************************************************************
2004-01-05 22:36:02 +03:00
Try to get the disk space from disk quotas ( LINUX version ) .
1996-05-05 15:25:33 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-06-11 05:03:06 +04:00
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1996-05-05 15:25:33 +04:00
{
2001-09-22 02:06:03 +04:00
int r ;
SMB_STRUCT_STAT S ;
FILE * fp ;
LINUX_SMB_DISK_QUOTA D ;
struct mntent * mnt ;
SMB_DEV_T devno ;
int found ;
uid_t euser_id ;
2004-01-05 22:36:02 +03:00
gid_t egrp_id ;
2001-09-22 02:06:03 +04:00
euser_id = geteuid ( ) ;
2004-01-05 22:36:02 +03:00
egrp_id = getegid ( ) ;
2001-09-22 02:06:03 +04:00
/* find the block device file */
1996-05-05 15:25:33 +04:00
2001-09-22 02:06:03 +04:00
if ( sys_stat ( path , & S ) = = - 1 )
return ( False ) ;
1996-05-05 15:25:33 +04:00
2001-09-22 02:06:03 +04:00
devno = S . st_dev ;
1996-05-05 15:25:33 +04:00
2001-09-22 02:06:03 +04:00
fp = setmntent ( MOUNTED , " r " ) ;
found = False ;
1996-05-05 15:25:33 +04:00
2001-09-22 02:06:03 +04:00
while ( ( mnt = getmntent ( fp ) ) ) {
if ( sys_stat ( mnt - > mnt_dir , & S ) = = - 1 )
continue ;
if ( S . st_dev = = devno ) {
found = True ;
break ;
}
}
endmntent ( fp ) ;
1996-05-05 15:25:33 +04:00
2001-09-22 02:06:03 +04:00
if ( ! found )
return ( False ) ;
save_re_uid ( ) ;
set_effective_uid ( 0 ) ;
2004-01-05 22:36:02 +03:00
if ( strcmp ( mnt - > mnt_type , " xfs " ) = = 0 ) {
r = get_smb_linux_xfs_quota ( mnt - > mnt_fsname , euser_id , egrp_id , & D ) ;
} else {
r = get_smb_linux_gen_quota ( mnt - > mnt_fsname , euser_id , egrp_id , & D ) ;
if ( r = = - 1 & & errno ! = EDQUOT ) {
r = get_smb_linux_v2_quota ( mnt - > mnt_fsname , euser_id , egrp_id , & D ) ;
if ( r = = - 1 & & errno ! = EDQUOT )
r = get_smb_linux_v1_quota ( mnt - > mnt_fsname , euser_id , egrp_id , & D ) ;
}
}
2001-09-22 02:06:03 +04:00
restore_re_uid ( ) ;
/* 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 ) ;
1996-05-05 15:25:33 +04:00
}
# elif defined(CRAY)
1996-05-31 19:13:29 +04:00
# include <sys/quota.h>
# include <mntent.h>
1996-05-05 15:25:33 +04:00
/****************************************************************************
try to get the disk space from disk quotas ( CRAY VERSION )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-06 21:40:51 +03:00
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1996-05-05 15:25:33 +04:00
{
struct mntent * mnt ;
FILE * fd ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT sbuf ;
1998-09-03 22:40:31 +04:00
SMB_DEV_T devno ;
static SMB_DEV_T devno_cached = 0 ;
1998-05-12 04:55:32 +04:00
static pstring name ;
1996-05-05 15:25:33 +04:00
struct q_request request ;
struct qf_header header ;
static int quota_default = 0 ;
int found ;
1998-09-03 22:40:31 +04:00
if ( sys_stat ( path , & sbuf ) = = - 1 )
1996-05-05 15:25:33 +04:00
return ( False ) ;
devno = sbuf . st_dev ;
if ( devno ! = devno_cached ) {
devno_cached = devno ;
if ( ( fd = setmntent ( KMTAB ) ) = = NULL )
return ( False ) ;
found = False ;
while ( ( mnt = getmntent ( fd ) ) ! = NULL ) {
1998-09-03 22:40:31 +04:00
if ( sys_stat ( mnt - > mnt_dir , & sbuf ) = = - 1 )
1996-05-05 15:25:33 +04:00
continue ;
if ( sbuf . st_dev = = devno ) {
found = True ;
break ;
}
}
1998-05-12 04:55:32 +04:00
pstrcpy ( name , mnt - > mnt_dir ) ;
1996-05-05 15:25:33 +04:00
endmntent ( fd ) ;
if ( ! found )
return ( False ) ;
}
request . qf_magic = QF_MAGIC ;
request . qf_entry . id = geteuid ( ) ;
if ( quotactl ( name , Q_GETQUOTA , & request ) = = - 1 )
return ( False ) ;
if ( ! request . user )
return ( False ) ;
if ( request . qf_entry . user_q . f_quota = = QFV_DEFAULT ) {
if ( ! quota_default ) {
if ( quotactl ( name , Q_GETHEADER , & header ) = = - 1 )
return ( False ) ;
else
quota_default = header . user_h . def_fq ;
}
* dfree = quota_default ;
} else if ( request . qf_entry . user_q . f_quota = = QFV_PREVENT ) {
* dfree = 0 ;
} else {
* dfree = request . qf_entry . user_q . f_quota ;
}
* dsize = request . qf_entry . user_q . f_use ;
1999-12-13 16:27:58 +03:00
if ( * dfree < * dsize )
1996-05-05 15:25:33 +04:00
* dfree = 0 ;
1999-12-13 16:27:58 +03:00
else
* dfree - = * dsize ;
1996-05-05 15:25:33 +04:00
* bsize = 4096 ; /* Cray blocksize */
return ( True ) ;
}
1996-06-08 08:33:37 +04:00
# elif defined(SUNOS5) || defined(SUNOS4)
1996-05-05 15:25:33 +04:00
# include <fcntl.h>
1998-11-06 21:40:51 +03:00
# include <sys/param.h>
1996-06-08 08:33:37 +04:00
# if defined(SUNOS5)
1996-05-05 15:25:33 +04:00
# include <sys/fs/ufs_quota.h>
1996-06-08 08:33:37 +04:00
# include <sys/mnttab.h>
2001-02-28 00:46:01 +03:00
# include <sys/mntent.h>
1996-06-08 08:33:37 +04:00
# else /* defined(SUNOS4) */
# include <ufs/quota.h>
# include <mntent.h>
# endif
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04: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>
static int quotastat ;
static int 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 ) ;
}
static int xdr_getquota_rslt ( XDR * xdrsp , struct getquota_rslt * gqr )
{
if ( ! xdr_int ( xdrsp , & quotastat ) ) {
DEBUG ( 6 , ( " nfs_quotas: Status bad or zero \n " ) ) ;
return 0 ;
}
2001-04-06 00:46:15 +04:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsize ) ) {
2001-04-01 23:00:43 +04: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-06 00:46:15 +04:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bhardlimit ) ) {
2001-04-01 23:00:43 +04:00
DEBUG ( 6 , ( " nfs_quotas: Hardlimit bad or zero \n " ) ) ;
return 0 ;
}
2001-04-06 00:46:15 +04:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsoftlimit ) ) {
2001-04-01 23:00:43 +04:00
DEBUG ( 6 , ( " nfs_quotas: Softlimit bad or zero \n " ) ) ;
return 0 ;
}
2001-04-06 00:46:15 +04:00
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_curblocks ) ) {
2001-04-01 23:00:43 +04:00
DEBUG ( 6 , ( " nfs_quotas: Currentblocks bad or zero \n " ) ) ;
return 0 ;
}
return ( 1 ) ;
}
/* Restricted to SUNOS5 for the moment, I haven`t access to others to test. */
static BOOL nfs_quotas ( char * nfspath , uid_t euser_id , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
{
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 ;
2001-04-27 23:56:15 +04:00
BOOL ret = True ;
* bsize = * dfree = * dsize = ( SMB_BIG_UINT ) 0 ;
2001-04-01 23:00:43 +04:00
len = strcspn ( mnttype , " : " ) ;
pathname = strstr ( mnttype , " : " ) ;
2004-12-21 04:04:11 +03:00
cutstr = ( char * ) SMB_MALLOC ( len + 1 ) ;
2001-04-01 23:00:43 +04:00
if ( ! cutstr )
return False ;
2003-03-11 21:10:27 +03:00
memset ( cutstr , ' \0 ' , len + 1 ) ;
2001-04-01 23:00:43 +04: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 11:36:09 +04:00
testpath = strchr_m ( mnttype , ' : ' ) ;
2001-04-01 23:00:43 +04: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 23:56:15 +04: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 23:00:43 +04:00
2001-04-27 23:56:15 +04:00
clnt_stat = clnt_call ( clnt , RQUOTAPROC_GETQUOTA , xdr_getquota_args , ( caddr_t ) & args , xdr_getquota_rslt , ( caddr_t ) & gqr , timeout ) ;
2001-04-01 23:00:43 +04:00
2001-04-27 23:56:15 +04:00
if ( clnt_stat ! = RPC_SUCCESS ) {
DEBUG ( 9 , ( " nfs_quotas: clnt_call fail \n " ) ) ;
ret = False ;
goto out ;
}
2001-04-01 23:00:43 +04:00
/*
* quotastat returns 0 if the rpc call fails , 1 if quotas exist , 2 if there is
* no quota set , and 3 if no permission to get the quota . If 0 or 3 return
* something sensible .
*/
2001-04-27 23:56:15 +04:00
switch ( quotastat ) {
case 0 :
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Failed! Error \" %i \" \n " , quotastat ) ) ;
ret = False ;
goto out ;
case 1 :
2001-04-01 23:00:43 +04: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 23:56:15 +04:00
break ;
2001-04-01 23:00:43 +04:00
2001-04-27 23:56:15 +04:00
case 2 :
case 3 :
2001-04-01 23:00:43 +04:00
D . dqb_bsoftlimit = 1 ;
D . dqb_curblocks = 1 ;
2001-04-27 23:56:15 +04:00
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas returned \" %i \" \n " , quotastat ) ) ;
break ;
2001-04-01 23:00:43 +04:00
2001-04-27 23:56:15 +04:00
default :
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Questionable! Error \" %i \" \n " , quotastat ) ) ;
break ;
}
2001-04-01 23:00:43 +04: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 " ,
quotastat ,
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_curblocks = = 1 )
* bsize = 512 ;
if ( D . dqb_curblocks > D . dqb_bsoftlimit ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
} else
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
2001-04-27 23:56:15 +04:00
out :
if ( clnt ) {
if ( clnt - > cl_auth )
auth_destroy ( clnt - > cl_auth ) ;
clnt_destroy ( clnt ) ;
}
2001-04-01 23:00:43 +04: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 15:25:41 +04:00
SAFE_FREE ( cutstr ) ;
2001-04-01 23:00:43 +04:00
DEBUG ( 10 , ( " nfs_quotas: End of nfs_quotas \n " ) ) ;
2001-04-27 23:56:15 +04:00
return ret ;
2001-04-01 23:00:43 +04:00
}
# endif
1996-05-05 15:25:33 +04:00
/****************************************************************************
1998-11-06 21:40:51 +03:00
try to get the disk space from disk quotas ( SunOS & Solaris2 version )
1998-11-09 23:33:37 +03:00
Quota code by Peter Urbanec ( amiga @ cse . unsw . edu . au ) .
1998-11-06 21:40:51 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1996-05-05 15:25:33 +04:00
{
2001-04-01 23:00:43 +04:00
uid_t euser_id ;
int ret ;
struct dqblk D ;
1996-06-08 08:33:37 +04:00
# if defined(SUNOS5)
2001-04-01 23:00:43 +04:00
struct quotctl command ;
int file ;
static struct mnttab mnt ;
static pstring name ;
pstring devopt ;
1998-11-06 21:40:51 +03:00
# else /* SunOS4 */
2001-04-01 23:00:43 +04:00
struct mntent * mnt ;
static pstring name ;
1996-06-08 08:33:37 +04:00
# endif
2001-04-01 23:00:43 +04:00
FILE * fd ;
SMB_STRUCT_STAT sbuf ;
SMB_DEV_T devno ;
static SMB_DEV_T devno_cached = 0 ;
static int found ;
1999-12-13 16:27:58 +03:00
2001-04-01 23:00:43 +04:00
euser_id = geteuid ( ) ;
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
if ( sys_stat ( path , & sbuf ) = = - 1 )
return ( False ) ;
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
devno = sbuf . st_dev ;
2001-04-28 02:17:10 +04:00
DEBUG ( 5 , ( " disk_quotas: looking for path \" %s \" devno=%x \n " , path , ( unsigned int ) devno ) ) ;
2001-04-01 23:00:43 +04:00
if ( devno ! = devno_cached ) {
devno_cached = devno ;
1996-06-08 08:33:37 +04:00
# if defined(SUNOS5)
2001-04-01 23:00:43 +04:00
if ( ( fd = sys_fopen ( MNTTAB , " r " ) ) = = NULL )
return ( False ) ;
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
found = False ;
2001-04-28 02:17:10 +04:00
slprintf ( devopt , sizeof ( devopt ) - 1 , " dev=%x " , ( unsigned int ) devno ) ;
2001-04-01 23:00:43 +04:00
while ( getmntent ( fd , & mnt ) = = 0 ) {
if ( ! hasmntopt ( & mnt , devopt ) )
continue ;
DEBUG ( 5 , ( " disk_quotas: testing \" %s \" %s \n " , mnt . mnt_mountp , devopt ) ) ;
/* quotas are only on vxfs, UFS or NFS */
if ( strcmp ( mnt . mnt_fstype , MNTTYPE_UFS ) = = 0 | |
strcmp ( mnt . mnt_fstype , " nfs " ) = = 0 | |
strcmp ( mnt . mnt_fstype , " vxfs " ) = = 0 ) {
found = True ;
break ;
}
}
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
pstrcpy ( name , mnt . mnt_mountp ) ;
pstrcat ( name , " /quotas " ) ;
fclose ( fd ) ;
1998-11-06 21:40:51 +03:00
# else /* SunOS4 */
2001-04-01 23:00:43 +04:00
if ( ( fd = setmntent ( MOUNTED , " r " ) ) = = NULL )
return ( False ) ;
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
found = False ;
while ( ( mnt = getmntent ( fd ) ) ! = NULL ) {
if ( sys_stat ( mnt - > mnt_dir , & sbuf ) = = - 1 )
continue ;
2001-04-28 02:17:10 +04:00
DEBUG ( 5 , ( " disk_quotas: testing \" %s \" devno=%x \n " , mnt - > mnt_dir , ( unsigned int ) sbuf . st_dev ) ) ;
2001-04-01 23:00:43 +04:00
if ( sbuf . st_dev = = devno ) {
found = True ;
break ;
}
}
1996-06-08 08:33:37 +04:00
2001-04-01 23:00:43 +04:00
pstrcpy ( name , mnt - > mnt_fsname ) ;
endmntent ( fd ) ;
1996-06-08 08:33:37 +04:00
# endif
2001-04-01 23:00:43 +04:00
}
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04:00
if ( ! found )
return ( False ) ;
2001-02-28 00:46:01 +03:00
2001-04-01 23:00:43 +04:00
save_re_uid ( ) ;
set_effective_uid ( 0 ) ;
1996-05-31 19:13:29 +04:00
1996-06-08 08:33:37 +04:00
# if defined(SUNOS5)
2001-04-01 23:00:43 +04:00
if ( strcmp ( mnt . mnt_fstype , " nfs " ) = = 0 ) {
BOOL retval ;
DEBUG ( 5 , ( " disk_quotas: looking for mountpath (NFS) \" %s \" \n " , mnt . mnt_special ) ) ;
retval = nfs_quotas ( mnt . mnt_special , euser_id , bsize , dfree , dsize ) ;
restore_re_uid ( ) ;
return retval ;
}
DEBUG ( 5 , ( " disk_quotas: looking for quotas file \" %s \" \n " , name ) ) ;
if ( ( file = sys_open ( name , O_RDONLY , 0 ) ) < 0 ) {
restore_re_uid ( ) ;
return ( False ) ;
}
command . op = Q_GETQUOTA ;
command . uid = euser_id ;
command . addr = ( caddr_t ) & D ;
ret = ioctl ( file , Q_QUOTACTL , & command ) ;
close ( file ) ;
1996-06-08 08:33:37 +04:00
# else
2001-04-01 23:00:43 +04:00
DEBUG ( 5 , ( " disk_quotas: trying quotactl on device \" %s \" \n " , name ) ) ;
ret = quotactl ( Q_GETQUOTA , name , euser_id , & D ) ;
1996-06-08 08:33:37 +04:00
# endif
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04:00
restore_re_uid ( ) ;
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04:00
if ( ret < 0 ) {
DEBUG ( 5 , ( " disk_quotas ioctl (Solaris) failed. Error = %s \n " , strerror ( errno ) ) ) ;
2000-03-13 20:38:13 +03:00
# if defined(SUNOS5) && defined(VXFS_QUOTA)
2001-04-01 23:00:43 +04: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 " ) ) {
BOOL retval ;
retval = disk_quotas_vxfs ( name , path , bsize , dfree , dsize ) ;
return ( retval ) ;
}
2000-03-13 20:38:13 +03:00
# else
2001-04-01 23:00:43 +04:00
return ( False ) ;
2000-03-13 20:38:13 +03:00
# endif
2001-04-01 23:00:43 +04:00
}
1996-05-31 19:13:29 +04:00
2001-04-01 23:00:43 +04:00
/* If softlimit is zero, set it equal to hardlimit.
*/
2000-04-11 01:02:45 +04:00
2001-04-01 23:00:43 +04:00
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
/* 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 : - )
*/
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 ;
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04:00
DEBUG ( 5 , ( " disk_quotas for path \" %s \" returning bsize %.0f, dfree %.0f, dsize %.0f \n " ,
path , ( double ) * bsize , ( double ) * dfree , ( double ) * dsize ) ) ;
1996-05-05 15:25:33 +04:00
2001-04-01 23:00:43 +04:00
return ( True ) ;
1996-05-05 15:25:33 +04:00
}
1997-08-19 23:22:26 +04:00
# elif defined(OSF1)
# include <ufs/quota.h>
/****************************************************************************
1998-11-13 05:07:07 +03:00
try to get the disk space from disk quotas - OSF1 version
1997-08-19 23:22:26 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-06 21:40:51 +03:00
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1997-08-19 23:22:26 +04:00
{
1997-09-23 23:19:06 +04:00
int r , save_errno ;
1997-08-19 23:22:26 +04:00
struct dqblk D ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT S ;
1999-12-13 16:27:58 +03:00
uid_t euser_id ;
1997-08-19 23:22:26 +04:00
1999-12-13 16:27:58 +03:00
/*
* This code presumes that OSF1 will only
* give out quota info when the real uid
* matches the effective uid . JRA .
*/
1997-08-19 23:22:26 +04:00
euser_id = geteuid ( ) ;
1999-12-13 16:27:58 +03:00
save_re_uid ( ) ;
if ( set_re_uid ( ) ! = 0 ) return False ;
1997-08-19 23:22:26 +04:00
r = quotactl ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) , euser_id , ( char * ) & D ) ;
1999-12-13 16:27:58 +03:00
if ( r ) {
1997-09-23 23:19:06 +04:00
save_errno = errno ;
1999-12-13 16:27:58 +03:00
}
1997-09-23 23:19:06 +04:00
1999-12-13 16:27:58 +03:00
restore_re_uid ( ) ;
1997-08-19 23:22:26 +04:00
* bsize = DEV_BSIZE ;
if ( r )
1997-09-23 23:19:06 +04:00
{
2000-12-04 20:16:44 +03:00
if ( save_errno = = EDQUOT ) /* disk quota exceeded */
1997-09-23 23:19:06 +04:00
{
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
return ( True ) ;
}
else
return ( False ) ;
}
1997-08-19 23:22:26 +04:00
2000-04-11 01:02:45 +04:00
/* If softlimit is zero, set it equal to hardlimit.
*/
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
1997-08-19 23:22:26 +04:00
/* Use softlimit to determine disk space, except when it has been exceeded */
if ( D . dqb_bsoftlimit = = 0 )
return ( False ) ;
if ( ( D . dqb_curblocks > D . dqb_bsoftlimit ) ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
} else {
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
* dsize = D . dqb_bsoftlimit ;
}
return ( True ) ;
}
1997-10-09 00:34:13 +04:00
1999-12-13 16:27:58 +03:00
# elif defined (IRIX6)
1997-10-09 00:34:13 +04:00
/****************************************************************************
try to get the disk space from disk quotas ( IRIX 6.2 version )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include <sys/quota.h>
# include <mntent.h>
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1997-10-09 00:34:13 +04:00
{
uid_t euser_id ;
int r ;
struct dqblk D ;
struct fs_disk_quota F ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT S ;
1997-10-09 00:34:13 +04:00
FILE * fp ;
struct mntent * mnt ;
1998-09-03 22:40:31 +04:00
SMB_DEV_T devno ;
1997-10-09 00:34:13 +04:00
int found ;
/* find the block device file */
1998-09-03 22:40:31 +04:00
if ( sys_stat ( path , & S ) = = - 1 ) {
1997-10-09 00:34:13 +04:00
return ( False ) ;
}
devno = S . st_dev ;
fp = setmntent ( MOUNTED , " r " ) ;
found = False ;
while ( ( mnt = getmntent ( fp ) ) ) {
1998-09-03 22:40:31 +04:00
if ( sys_stat ( mnt - > mnt_dir , & S ) = = - 1 )
1997-10-09 00:34:13 +04:00
continue ;
if ( S . st_dev = = devno ) {
found = True ;
break ;
}
}
endmntent ( fp ) ;
if ( ! found ) {
return ( False ) ;
}
euser_id = geteuid ( ) ;
1999-12-13 16:27:58 +03:00
save_re_uid ( ) ;
set_effective_uid ( 0 ) ;
1997-10-09 00:34:13 +04:00
/* Use softlimit to determine disk space, except when it has been exceeded */
* bsize = 512 ;
if ( 0 = = strcmp ( mnt - > mnt_type , " efs " ) )
{
r = quotactl ( Q_GETQUOTA , mnt - > mnt_fsname , euser_id , ( caddr_t ) & D ) ;
1999-12-13 16:27:58 +03:00
restore_re_uid ( ) ;
1997-11-17 22:16:38 +03:00
1997-10-09 00:34:13 +04:00
if ( r = = - 1 )
return ( False ) ;
/* Use softlimit to determine disk space, except when it has been exceeded */
if (
( D . dqb_bsoftlimit & & D . dqb_curblocks > = D . dqb_bsoftlimit ) | |
( D . dqb_bhardlimit & & D . dqb_curblocks > = D . dqb_bhardlimit ) | |
( D . dqb_fsoftlimit & & D . dqb_curfiles > = D . dqb_fsoftlimit ) | |
( D . dqb_fhardlimit & & D . dqb_curfiles > = D . dqb_fhardlimit )
)
{
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
}
else if ( D . dqb_bsoftlimit = = 0 & & D . dqb_bhardlimit = = 0 )
{
return ( False ) ;
}
else
{
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
* dsize = D . dqb_bsoftlimit ;
}
}
else if ( 0 = = strcmp ( mnt - > mnt_type , " xfs " ) )
{
r = quotactl ( Q_XGETQUOTA , mnt - > mnt_fsname , euser_id , ( caddr_t ) & F ) ;
1999-12-13 16:27:58 +03:00
restore_re_uid ( ) ;
1997-11-17 22:16:38 +03:00
1997-10-09 00:34:13 +04:00
if ( r = = - 1 )
2005-03-22 20:31:23 +03:00
{
DEBUG ( 5 , ( " quotactl for uid=%u: %s " , euser_id , strerror ( errno ) ) ) ;
1997-10-09 00:34:13 +04:00
return ( False ) ;
2005-03-22 20:31:23 +03:00
}
1997-10-09 00:34:13 +04:00
2005-03-22 20:31:23 +03:00
/* No quota for this user. */
if ( F . d_blk_softlimit = = 0 & & F . d_blk_hardlimit = = 0 )
{
return ( False ) ;
}
1997-10-09 00:34:13 +04:00
/* Use softlimit to determine disk space, except when it has been exceeded */
if (
( F . d_blk_softlimit & & F . d_bcount > = F . d_blk_softlimit ) | |
( F . d_blk_hardlimit & & F . d_bcount > = F . d_blk_hardlimit ) | |
( F . d_ino_softlimit & & F . d_icount > = F . d_ino_softlimit ) | |
( F . d_ino_hardlimit & & F . d_icount > = F . d_ino_hardlimit )
)
{
* dfree = 0 ;
1998-11-06 21:40:51 +03:00
* dsize = F . d_bcount ;
1997-10-09 00:34:13 +04:00
}
else
{
1998-11-06 21:40:51 +03:00
* dfree = ( F . d_blk_softlimit - F . d_bcount ) ;
2005-03-22 20:31:23 +03:00
* dsize = F . d_blk_softlimit ? F . d_blk_softlimit : F . d_blk_hardlimit ;
1997-10-09 00:34:13 +04:00
}
}
else
1997-11-17 22:16:38 +03:00
{
1999-12-13 16:27:58 +03:00
restore_re_uid ( ) ;
return ( False ) ;
1997-11-17 22:16:38 +03:00
}
1997-10-09 00:34:13 +04:00
return ( True ) ;
}
1996-05-05 15:25:33 +04:00
# else
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1996-12-10 20:58:11 +03:00
# include <ufs/ufs/quota.h>
1997-10-09 00:34:13 +04:00
# include <machine/param.h>
1997-07-08 20:54:44 +04:00
# elif AIX
/* 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
2005-05-10 19:42:32 +04:00
# else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1996-05-31 19:13:29 +04:00
# include <sys/quota.h>
# include <devnm.h>
1996-12-10 20:58:11 +03:00
# endif
1996-05-31 19:13:29 +04:00
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__DragonFly__)
2004-07-04 03:53:36 +04:00
# include <rpc/rpc.h>
# include <rpc/types.h>
# include <rpcsvc/rquota.h>
2005-02-01 21:14:15 +03:00
# ifdef HAVE_RPC_NETTYPE_H
2004-07-04 03:53:36 +04:00
# include <rpc/nettype.h>
2005-02-01 21:14:15 +03:00
# endif
2004-07-04 03:53:36 +04:00
# include <rpc/xdr.h>
static int quotastat ;
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 ) ;
}
static int my_xdr_getquota_rslt ( XDR * xdrsp , struct getquota_rslt * gqr )
{
if ( ! xdr_int ( xdrsp , & quotastat ) ) {
DEBUG ( 6 , ( " nfs_quotas: Status bad or zero \n " ) ) ;
return 0 ;
}
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsize ) ) {
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 ;
}
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bhardlimit ) ) {
DEBUG ( 6 , ( " nfs_quotas: Hardlimit bad or zero \n " ) ) ;
return 0 ;
}
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_bsoftlimit ) ) {
DEBUG ( 6 , ( " nfs_quotas: Softlimit bad or zero \n " ) ) ;
return 0 ;
}
if ( ! xdr_int ( xdrsp , & gqr - > getquota_rslt_u . gqr_rquota . rq_curblocks ) ) {
DEBUG ( 6 , ( " nfs_quotas: Currentblocks bad or zero \n " ) ) ;
return 0 ;
}
return ( 1 ) ;
}
/* Works on FreeBSD, too. :-) */
static BOOL nfs_quotas ( char * nfspath , uid_t euser_id , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
{
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 ;
BOOL ret = True ;
* bsize = * dfree = * dsize = ( SMB_BIG_UINT ) 0 ;
len = strcspn ( mnttype , " : " ) ;
pathname = strstr ( mnttype , " : " ) ;
2004-12-21 04:04:11 +03:00
cutstr = ( char * ) SMB_MALLOC ( len + 1 ) ;
2004-07-04 03:53:36 +04:00
if ( ! cutstr )
return False ;
memset ( cutstr , ' \0 ' , len + 1 ) ;
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 ) ) ;
testpath = strchr_m ( mnttype , ' : ' ) ;
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 " ) ) ;
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 " ) ) ;
clnt_stat = clnt_call ( clnt , RQUOTAPROC_GETQUOTA , ( const xdrproc_t ) my_xdr_getquota_args , ( caddr_t ) & args , ( const xdrproc_t ) my_xdr_getquota_rslt , ( caddr_t ) & gqr , timeout ) ;
if ( clnt_stat ! = RPC_SUCCESS ) {
DEBUG ( 9 , ( " nfs_quotas: clnt_call fail \n " ) ) ;
ret = False ;
goto out ;
}
/*
* quotastat returns 0 if the rpc call fails , 1 if quotas exist , 2 if there is
* no quota set , and 3 if no permission to get the quota . If 0 or 3 return
* something sensible .
*/
switch ( quotastat ) {
case 0 :
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Failed! Error \" %i \" \n " , quotastat ) ) ;
ret = False ;
goto out ;
case 1 :
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 ;
break ;
case 2 :
case 3 :
D . dqb_bsoftlimit = 1 ;
D . dqb_curblocks = 1 ;
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas returned \" %i \" \n " , quotastat ) ) ;
break ;
default :
DEBUG ( 9 , ( " nfs_quotas: Remote Quotas Questionable! Error \" %i \" \n " , quotastat ) ) ;
break ;
}
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 " ,
quotastat ,
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 ) ) ;
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
if ( D . dqb_bsoftlimit = = 0 )
return False ;
* bsize = gqr . getquota_rslt_u . gqr_rquota . rq_bsize ;
* dsize = D . dqb_bsoftlimit ;
if ( D . dqb_curblocks = = D . dqb_curblocks = = 1 )
* bsize = DEV_BSIZE ;
if ( D . dqb_curblocks > D . dqb_bsoftlimit ) {
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
} else
* dfree = D . dqb_bsoftlimit - D . dqb_curblocks ;
out :
if ( clnt ) {
if ( clnt - > cl_auth )
auth_destroy ( clnt - > cl_auth ) ;
clnt_destroy ( clnt ) ;
}
DEBUG ( 5 , ( " nfs_quotas: For path \" %s \" returning bsize %.0f, dfree %.0f, dsize %.0f \n " , args . gqa_pathp , ( double ) * bsize , ( double ) * dfree , ( double ) * dsize ) ) ;
SAFE_FREE ( cutstr ) ;
DEBUG ( 10 , ( " nfs_quotas: End of nfs_quotas \n " ) ) ;
return ret ;
}
# endif
1996-05-05 15:25:33 +04:00
/****************************************************************************
try to get the disk space from disk quotas - default version
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-11-06 21:40:51 +03:00
2001-11-04 02:34:24 +03:00
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
1996-05-05 15:25:33 +04:00
{
int r ;
struct dqblk D ;
1999-12-13 16:27:58 +03:00
uid_t euser_id ;
2005-05-10 19:42:32 +04:00
# if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1997-07-02 05:19:41 +04:00
char dev_disk [ 256 ] ;
1998-09-02 00:11:54 +04:00
SMB_STRUCT_STAT S ;
2003-01-28 05:15:11 +03:00
1996-05-05 15:25:33 +04:00
/* find the block device file */
2003-01-28 05:15:11 +03:00
# ifdef HPUX
/* Need to set the cache flag to 1 for HPUX. Seems
* to have a significant performance boost when
* lstat calls on / dev access this function .
*/
if ( ( sys_stat ( path , & S ) < 0 ) | | ( devnm ( S_IFBLK , S . st_dev , dev_disk , 256 , 1 ) < 0 ) )
# else
if ( ( sys_stat ( path , & S ) < 0 ) | | ( devnm ( S_IFBLK , S . st_dev , dev_disk , 256 , 0 ) < 0 ) )
2003-05-01 15:02:54 +04:00
return ( False ) ;
2004-01-05 22:36:02 +03:00
# endif /* ifdef HPUX */
2003-01-28 05:15:11 +03:00
2005-05-10 19:42:32 +04:00
# endif /* !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__) && !defined(__DragonFly__) */
1996-05-05 15:25:33 +04:00
euser_id = geteuid ( ) ;
1998-07-29 07:08:05 +04:00
# ifdef HPUX
1999-12-13 16:27:58 +03:00
/* for HPUX, real uid must be same as euid to execute quotactl for euid */
save_re_uid ( ) ;
if ( set_re_uid ( ) ! = 0 ) return False ;
r = quotactl ( Q_GETQUOTA , dev_disk , euser_id , & D ) ;
restore_re_uid ( ) ;
1998-07-29 07:08:05 +04:00
# else
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1997-10-09 00:34:13 +04:00
{
/* FreeBSD patches from Marty Moll <martym@arbor.edu> */
gid_t egrp_id ;
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__DragonFly__)
2004-07-04 03:53:36 +04:00
SMB_DEV_T devno ;
struct statfs * mnts ;
SMB_STRUCT_STAT st ;
int mntsize , i ;
if ( sys_stat ( path , & st ) < 0 )
return False ;
devno = st . st_dev ;
mntsize = getmntinfo ( & mnts , MNT_NOWAIT ) ;
if ( mntsize < = 0 )
return False ;
for ( i = 0 ; i < mntsize ; i + + ) {
if ( sys_stat ( mnts [ i ] . f_mntonname , & st ) < 0 )
return False ;
if ( st . st_dev = = devno )
break ;
}
if ( i = = mntsize )
return False ;
# endif
1999-12-13 16:27:58 +03:00
save_re_uid ( ) ;
set_effective_uid ( 0 ) ;
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__DragonFly__)
2004-07-04 03:53:36 +04:00
if ( strcmp ( mnts [ i ] . f_fstypename , " nfs " ) = = 0 ) {
BOOL retval ;
retval = nfs_quotas ( mnts [ i ] . f_mntfromname , euser_id , bsize , dfree , dsize ) ;
restore_re_uid ( ) ;
return retval ;
}
# endif
1997-10-09 00:34:13 +04:00
egrp_id = getegid ( ) ;
r = quotactl ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) , euser_id , ( char * ) & D ) ;
/* As FreeBSD has group quotas, if getting the user
quota fails , try getting the group instead . */
1999-12-13 16:27:58 +03:00
if ( r ) {
r = quotactl ( path , QCMD ( Q_GETQUOTA , GRPQUOTA ) , egrp_id , ( char * ) & D ) ;
}
restore_re_uid ( ) ;
1997-10-09 00:34:13 +04:00
}
1997-07-08 20:54:44 +04:00
# elif defined(AIX)
/* AIX has both USER and GROUP quotas:
Get the USER quota ( ohnielse @ fysik . dtu . dk ) */
2004-03-16 22:06:03 +03:00
save_re_uid ( ) ;
if ( set_re_uid ( ) ! = 0 )
return False ;
1997-07-08 20:54:44 +04:00
r = quotactl ( path , QCMD ( Q_GETQUOTA , USRQUOTA ) , euser_id , ( char * ) & D ) ;
2004-03-16 22:06:03 +03:00
restore_re_uid ( ) ;
2005-05-10 19:42:32 +04:00
# else /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1996-12-10 20:58:11 +03:00
r = quotactl ( Q_GETQUOTA , dev_disk , euser_id , & D ) ;
2005-05-10 19:42:32 +04:00
# endif /* !__FreeBSD__ && !AIX && !__OpenBSD__ && !__DragonFly__ */
1999-12-13 16:27:58 +03:00
# endif /* HPUX */
1996-12-10 20:58:11 +03:00
1996-05-05 15:25:33 +04:00
/* Use softlimit to determine disk space, except when it has been exceeded */
2005-05-10 19:42:32 +04:00
# if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
1997-10-09 00:34:13 +04:00
* bsize = DEV_BSIZE ;
2005-05-10 19:42:32 +04:00
# else /* !__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1996-05-05 15:25:33 +04:00
* bsize = 1024 ;
2005-05-10 19:42:32 +04:00
# endif /*!__FreeBSD__ && !__OpenBSD__ && !__DragonFly__ */
1997-10-09 00:34:13 +04:00
1996-05-05 15:25:33 +04:00
if ( r )
{
if ( errno = = EDQUOT )
{
* dfree = 0 ;
* dsize = D . dqb_curblocks ;
return ( True ) ;
}
else return ( False ) ;
}
2000-04-11 01:02:45 +04:00
/* If softlimit is zero, set it equal to hardlimit.
*/
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
1996-06-08 08:33:37 +04:00
if ( D . dqb_bsoftlimit = = 0 )
return ( False ) ;
1996-05-05 15:25:33 +04:00
/* Use softlimit to determine disk space, except when it has been exceeded */
1996-12-10 20:58:11 +03:00
if ( ( D . dqb_curblocks > D . dqb_bsoftlimit )
2005-05-10 19:42:32 +04:00
# if !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__)
1997-07-18 00:11:58 +04:00
| | ( ( D . dqb_curfiles > D . dqb_fsoftlimit ) & & ( D . dqb_fsoftlimit ! = 0 ) )
1996-12-10 20:58:11 +03:00
# endif
) {
1996-05-05 15:25:33 +04: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 20:38:13 +03: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>
BOOL disk_quotas_vxfs ( const pstring name , char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
{
uid_t user_id , euser_id ;
int ret ;
struct vx_dqblk D ;
struct vx_quotctl quotabuf ;
struct vx_genioctl genbuf ;
pstring qfname ;
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 .
*/
pstrcpy ( qfname , name ) ;
/* 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 ) ) ;
if ( ( file = sys_open ( qfname , O_RDONLY , 0 ) ) < 0 ) {
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-11 01:02:45 +04:00
/* If softlimit is zero, set it equal to hardlimit.
*/
if ( D . dqb_bsoftlimit = = 0 )
D . dqb_bsoftlimit = D . dqb_bhardlimit ;
2000-03-13 20:38:13 +03: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 05:20:17 +04:00
# else /* WITH_QUOTAS */
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
{
( * bsize ) = 512 ; /* This value should be ignored */
/* And just to be sure we set some values that hopefully */
/* will be larger that any possible real-world value */
( * dfree ) = ( SMB_BIG_UINT ) - 1 ;
( * dsize ) = ( SMB_BIG_UINT ) - 1 ;
/* As we have select not to use quotas, allways fail */
return False ;
}
# endif /* WITH_QUOTAS */
# else /* HAVE_SYS_QUOTAS */
/* wrapper to the new sys_quota interface
this file should be removed later
*/
BOOL disk_quotas ( const char * path , SMB_BIG_UINT * bsize , SMB_BIG_UINT * dfree , SMB_BIG_UINT * dsize )
{
int r ;
SMB_DISK_QUOTA D ;
unid_t id ;
id . uid = geteuid ( ) ;
2004-01-15 11:49:30 +03:00
ZERO_STRUCT ( D ) ;
2003-05-12 05:20:17 +04: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 11:49:30 +03:00
ZERO_STRUCT ( D ) ;
2003-05-12 05:20:17 +04: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 */