From 7b4151e173323e6ebc05a7ccc1671ab88f4e1660 Mon Sep 17 00:00:00 2001 From: Richard Sharpe Date: Sat, 3 Jul 2004 23:53:36 +0000 Subject: r1333: NFS Quota support from Dan Peterson. (This used to be commit 609828444d9126d8a6e8ff43e4b3c19079a9eb56) --- source3/smbd/quotas.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 203 insertions(+), 1 deletion(-) (limited to 'source3/smbd/quotas.c') diff --git a/source3/smbd/quotas.c b/source3/smbd/quotas.c index e439c1e571a..3c4d4319f63 100644 --- a/source3/smbd/quotas.c +++ b/source3/smbd/quotas.c @@ -933,6 +933,176 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB #include #endif +#if defined(__FreeBSD__) + +#include +#include +#include +#include +#include + +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); +} + +/* 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, ":"); + 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; + } + + /* + * 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 + /**************************************************************************** try to get the disk space from disk quotas - default version ****************************************************************************/ @@ -976,10 +1146,42 @@ BOOL disk_quotas(const char *path, SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, SMB { /* FreeBSD patches from Marty Moll */ 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); -- cgit v1.2.1