#include "includes.h"
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_QUOTA
#ifndef HAVE_SYS_QUOTAS
#ifdef QUOTABLOCK_SIZE
#undef QUOTABLOCK_SIZE
#endif
#ifdef WITH_QUOTAS
#if defined(VXFS_QUOTA)
BOOL disk_quotas_vxfs(const pstring name, char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize);
#endif
#ifdef LINUX
#include <sys/types.h>
#include <mntent.h>
#include "samba_linux_quota.h"
#include "samba_xfs_quota.h"
typedef struct _LINUX_SMB_DISK_QUOTA {
SMB_BIG_UINT bsize;
SMB_BIG_UINT hardlimit;
SMB_BIG_UINT softlimit;
SMB_BIG_UINT curblocks;
SMB_BIG_UINT ihardlimit;
SMB_BIG_UINT isoftlimit;
SMB_BIG_UINT curinodes;
} LINUX_SMB_DISK_QUOTA;
static int get_smb_linux_xfs_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
{
struct fs_disk_quota D;
int ret;
ZERO_STRUCT(D);
ret = quotactl(QCMD(Q_XGETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
if (ret)
ret = quotactl(QCMD(Q_XGETQUOTA,GRPQUOTA), path, egrp_id, (caddr_t)&D);
if (ret)
return ret;
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;
return ret;
}
static int get_smb_linux_v1_quota(char *path, uid_t euser_id, gid_t egrp_id, LINUX_SMB_DISK_QUOTA *dp)
{
struct v1_kern_dqblk D;
int ret;
ZERO_STRUCT(D);
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;
ZERO_STRUCT(D);
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;
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_curspace) / dp->bsize;
return ret;
}
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);
ret = quotactl(QCMD(Q_GETQUOTA,USRQUOTA), path, euser_id, (caddr_t)&D);
if (ret && errno != EDQUOT)
ret = quotactl(QCMD(Q_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_curspace) / dp->bsize;
return ret;
}
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
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;
gid_t egrp_id;
euser_id = geteuid();
egrp_id = getegid();
if ( sys_stat(path, &S) == -1 )
return(False) ;
devno = S.st_dev ;
fp = setmntent(MOUNTED,"r");
found = False ;
while ((mnt = getmntent(fp))) {
if ( sys_stat(mnt->mnt_dir,&S) == -1 )
continue ;
if (S.st_dev == devno) {
found = True ;
break;
}
}
endmntent(fp) ;
if (!found)
return(False);
save_re_uid();
set_effective_uid(0);
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);
}
}
restore_re_uid();
*bsize = D.bsize;
if (r == -1) {
if (errno == EDQUOT) {
*dfree =0;
*dsize =D.curblocks;
return (True);
} else {
return(False);
}
}
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);
}
#elif defined(CRAY)
#include <sys/quota.h>
#include <mntent.h>
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
struct mntent *mnt;
FILE *fd;
SMB_STRUCT_STAT sbuf;
SMB_DEV_T devno ;
static SMB_DEV_T devno_cached = 0 ;
static pstring name;
struct q_request request ;
struct qf_header header ;
static int quota_default = 0 ;
int found ;
if ( sys_stat(path,&sbuf) == -1 )
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) {
if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
continue ;
if (sbuf.st_dev == devno) {
found = True ;
break ;
}
}
pstrcpy(name,mnt->mnt_dir) ;
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 ;
if ( *dfree < *dsize )
*dfree = 0 ;
else
*dfree -= *dsize ;
*bsize = 4096 ;
return(True) ;
}
#elif defined(SUNOS5) || defined(SUNOS4)
#include <fcntl.h>
#include <sys/param.h>
#if defined(SUNOS5)
#include <sys/fs/ufs_quota.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
#else
#include <ufs/quota.h>
#include <mntent.h>
#endif
#if defined(SUNOS5)
#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, "astat)) {
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);
}
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, ":");
cutstr = (char *) malloc(len+1);
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, xdr_getquota_args, (caddr_t)&args, xdr_getquota_rslt, (caddr_t)&gqr, timeout);
if (clnt_stat != RPC_SUCCESS) {
DEBUG(9,("nfs_quotas: clnt_call fail\n"));
ret = False;
goto out;
}
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));
*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;
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
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
uid_t euser_id;
int ret;
struct dqblk D;
#if defined(SUNOS5)
struct quotctl command;
int file;
static struct mnttab mnt;
static pstring name;
pstring devopt;
#else
struct mntent *mnt;
static pstring name;
#endif
FILE *fd;
SMB_STRUCT_STAT sbuf;
SMB_DEV_T devno ;
static SMB_DEV_T devno_cached = 0 ;
static int found ;
euser_id = geteuid();
if ( sys_stat(path,&sbuf) == -1 )
return(False) ;
devno = sbuf.st_dev ;
DEBUG(5,("disk_quotas: looking for path \"%s\" devno=%x\n", path,(unsigned int)devno));
if ( devno != devno_cached ) {
devno_cached = devno ;
#if defined(SUNOS5)
if ((fd = sys_fopen(MNTTAB, "r")) == NULL)
return(False) ;
found = False ;
slprintf(devopt, sizeof(devopt) - 1, "dev=%x", (unsigned int)devno);
while (getmntent(fd, &mnt) == 0) {
if( !hasmntopt(&mnt, devopt) )
continue;
DEBUG(5,("disk_quotas: testing \"%s\" %s\n", mnt.mnt_mountp,devopt));
if ( strcmp( mnt.mnt_fstype, MNTTYPE_UFS ) == 0 ||
strcmp( mnt.mnt_fstype, "nfs" ) == 0 ||
strcmp( mnt.mnt_fstype, "vxfs" ) == 0 ) {
found = True ;
break;
}
}
pstrcpy(name,mnt.mnt_mountp) ;
pstrcat(name,"/quotas") ;
fclose(fd) ;
#else
if ((fd = setmntent(MOUNTED, "r")) == NULL)
return(False) ;
found = False ;
while ((mnt = getmntent(fd)) != NULL) {
if ( sys_stat(mnt->mnt_dir,&sbuf) == -1 )
continue ;
DEBUG(5,("disk_quotas: testing \"%s\" devno=%x\n", mnt->mnt_dir,(unsigned int)sbuf.st_dev));
if (sbuf.st_dev == devno) {
found = True ;
break;
}
}
pstrcpy(name,mnt->mnt_fsname) ;
endmntent(fd) ;
#endif
}
if ( ! found )
return(False) ;
save_re_uid();
set_effective_uid(0);
#if defined(SUNOS5)
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);
#else
DEBUG(5,("disk_quotas: trying quotactl on device \"%s\"\n", name));
ret = quotactl(Q_GETQUOTA, name, euser_id, &D);
#endif
restore_re_uid();
if (ret < 0) {
DEBUG(5,("disk_quotas ioctl (Solaris) failed. Error = %s\n", strerror(errno) ));
#if defined(SUNOS5) && defined(VXFS_QUOTA)
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);
}
#else
return(False);
#endif
}
if (D.dqb_bsoftlimit==0)
D.dqb_bsoftlimit = D.dqb_bhardlimit;
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);
}
#elif defined(OSF1)
#include <ufs/quota.h>
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r, save_errno;
struct dqblk D;
SMB_STRUCT_STAT S;
uid_t euser_id;
euser_id = geteuid();
save_re_uid();
if (set_re_uid() != 0) return False;
r= quotactl(path,QCMD(Q_GETQUOTA, USRQUOTA),euser_id,(char *) &D);
if (r) {
save_errno = errno;
}
restore_re_uid();
*bsize = DEV_BSIZE;
if (r)
{
if (save_errno == EDQUOT)
{
*dfree = 0;
*dsize = D.dqb_curblocks;
return (True);
}
else
return (False);
}
if (D.dqb_bsoftlimit==0)
D.dqb_bsoftlimit = D.dqb_bhardlimit;
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);
}
#elif defined (IRIX6)
#include <sys/quota.h>
#include <mntent.h>
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
uid_t euser_id;
int r;
struct dqblk D;
struct fs_disk_quota F;
SMB_STRUCT_STAT S;
FILE *fp;
struct mntent *mnt;
SMB_DEV_T devno;
int found;
if ( sys_stat(path, &S) == -1 ) {
return(False) ;
}
devno = S.st_dev ;
fp = setmntent(MOUNTED,"r");
found = False ;
while ((mnt = getmntent(fp))) {
if ( sys_stat(mnt->mnt_dir,&S) == -1 )
continue ;
if (S.st_dev == devno) {
found = True ;
break ;
}
}
endmntent(fp) ;
if (!found) {
return(False);
}
euser_id=geteuid();
save_re_uid();
set_effective_uid(0);
*bsize = 512;
if ( 0 == strcmp ( mnt->mnt_type, "efs" ))
{
r=quotactl (Q_GETQUOTA, mnt->mnt_fsname, euser_id, (caddr_t) &D);
restore_re_uid();
if (r==-1)
return(False);
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);
restore_re_uid();
if (r==-1)
return(False);
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;
*dsize = F.d_bcount;
}
else if (F.d_blk_softlimit==0 && F.d_blk_hardlimit==0)
{
return(False);
}
else
{
*dfree = (F.d_blk_softlimit - F.d_bcount);
*dsize = F.d_blk_softlimit;
}
}
else
{
restore_re_uid();
return(False);
}
return (True);
}
#else
#if defined(__FreeBSD__) || defined(__OpenBSD__)
#include <ufs/ufs/quota.h>
#include <machine/param.h>
#elif AIX
#include <jfs/quota.h>
#define dqb_curfiles dqb_curinodes
#define dqb_fhardlimit dqb_ihardlimit
#define dqb_fsoftlimit dqb_isoftlimit
#else
#include <sys/quota.h>
#include <devnm.h>
#endif
#if defined(__FreeBSD__)
#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 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, "astat)) {
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);
}
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, ":");
cutstr = (char *) malloc(len+1);
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;
}
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
BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB_BIG_UINT *dsize)
{
int r;
struct dqblk D;
uid_t euser_id;
#if !defined(__FreeBSD__) && !defined(AIX) && !defined(__OpenBSD__)
char dev_disk[256];
SMB_STRUCT_STAT S;
#ifdef HPUX
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))
return (False);
#endif
#endif
euser_id = geteuid();
#ifdef HPUX
save_re_uid();
if (set_re_uid() != 0) return False;
r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
restore_re_uid();
#else
#if defined(__FreeBSD__) || defined(__OpenBSD__)
{
gid_t egrp_id;
#if defined(__FreeBSD__)
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
save_re_uid();
set_effective_uid(0);
#if defined(__FreeBSD__)
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
egrp_id = getegid();
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
if (r) {
r= quotactl(path,QCMD(Q_GETQUOTA,GRPQUOTA),egrp_id,(char *) &D);
}
restore_re_uid();
}
#elif defined(AIX)
save_re_uid();
if (set_re_uid() != 0)
return False;
r= quotactl(path,QCMD(Q_GETQUOTA,USRQUOTA),euser_id,(char *) &D);
restore_re_uid();
#else
r=quotactl(Q_GETQUOTA, dev_disk, euser_id, &D);
#endif
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__)
*bsize = DEV_BSIZE;
#else
*bsize = 1024;
#endif
if (r)
{
if (errno == EDQUOT)
{
*dfree =0;
*dsize =D.dqb_curblocks;
return (True);
}
else return(False);
}
if (D.dqb_bsoftlimit==0)
D.dqb_bsoftlimit = D.dqb_bhardlimit;
if (D.dqb_bsoftlimit==0)
return(False);
if ((D.dqb_curblocks>D.dqb_bsoftlimit)
#if !defined(__FreeBSD__) && !defined(__OpenBSD__)
||((D.dqb_curfiles>D.dqb_fsoftlimit) && (D.dqb_fsoftlimit != 0))
#endif
) {
*dfree = 0;
*dsize = D.dqb_curblocks;
}
else {
*dfree = D.dqb_bsoftlimit - D.dqb_curblocks;
*dsize = D.dqb_bsoftlimit;
}
return (True);
}
#endif
#if defined(VXFS_QUOTA)
#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;
pstrcpy(qfname, 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 *) "abuf;
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);
}
if (D.dqb_bsoftlimit==0)
D.dqb_bsoftlimit = D.dqb_bhardlimit;
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
#endif
#else
BOOL disk_quotas(const char *path,SMB_BIG_UINT *bsize,SMB_BIG_UINT *dfree,SMB_BIG_UINT *dsize)
{
(*bsize) = 512;
(*dfree) = (SMB_BIG_UINT)-1;
(*dsize) = (SMB_BIG_UINT)-1;
return False;
}
#endif
#else
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();
ZERO_STRUCT(D);
r=sys_get_quota(path, SMB_USER_QUOTA_TYPE, id, &D);
*bsize = D.bsize;
if (r == -1) {
if (errno == EDQUOT) {
*dfree =0;
*dsize =D.curblocks;
return (True);
} else {
goto try_group_quota;
}
}
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();
ZERO_STRUCT(D);
r=sys_get_quota(path, SMB_GROUP_QUOTA_TYPE, id, &D);
*bsize = D.bsize;
if (r == -1) {
if (errno == EDQUOT) {
*dfree =0;
*dsize =D.curblocks;
return (True);
} else {
return False;
}
}
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