Date: Tue, 07 Nov 2000 16:43:48 +0900 From: Hiroshi Suzuki Subject: [samba-jp:07788] NFS quota (RPC rquotad) patch To: samba-jp@samba.gr.jp Message-Id: <200011070743.eA77hmY28329@ja.n.sic.shibaura-it.ac.jp> 芝浦工大の鈴木といいます。 うちでは必要にせまられて、NFSマウントされたvolumeを samba を使って windows からも使っているんですが、この場合 --with-quotas しても容量が 意図した(ユーザ毎に設定したlimit)容量になりません。 で、この部分を rpc rquotad を使うようにして、意図した容量を返すように してみました。(SUNOS5(solaris)のみ。他のOSはちょっといじれば出来ると 思う) samba-2.0.7-ja-2.1/source/smbd/quotas.c に対する patch です。 *** quotas.c.orig Fri Oct 20 01:24:07 2000 --- quotas.c Tue Nov 7 15:56:23 2000 *************** *** 43,48 **** --- 43,59 ---- #endif /* VXFS_QUOTA */ + #define RPC_QUOTA + #if defined(RPC_QUOTA) + /* + * remote quota server for NFS + */ + static BOOL disk_quotas_rquota(char *rhost, char *rpath, uid_t euser_id, + SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, + SMB_BIG_UINT *dsize); + + #endif /* RPC_QUOTA */ + #ifdef LINUX #include *************** *** 266,271 **** --- 277,286 ---- int file; static struct mnttab mnt; static pstring name; + #if defined(RPC_QUOTA) + static char *rhost = NULL; + static char *rpath = NULL; + #endif /* RPC_QUOTA */ #else /* SunOS4 */ struct mntent *mnt; static pstring name; *************** *** 301,308 **** --- 316,326 ---- } } + #if defined(RPC_QUOTA) + #else /* RPC_QUOTA */ pstrcpy(name,mnt.mnt_mountp) ; pstrcat(name,"/quotas") ; + #endif /* RPC_QUOTA */ fclose(fd) ; #else /* SunOS4 */ if ((fd = setmntent(MOUNTED, "r")) == NULL) *************** *** 326,331 **** --- 344,367 ---- if ( ! found ) return(False) ; + #if defined(RPC_QUOTA) + DEBUG(5,("disk_quotas: fstype='%s'\n", sbuf.st_fstype)); + if (strncmp(sbuf.st_fstype, "nfs", 3) == 0) { + /* remote quota */ + pstrcpy(name,mnt.mnt_special) ; + if ((rpath = strchr(name, ':')) == NULL) + return(False); + if (*(rpath+1) != '/') + return(False); + rhost = name; + *rpath = '\0'; + rpath = rpath+1; + } else { + /* local quota */ + pstrcpy(name,mnt.mnt_mountp) ; + pstrcat(name,"/quotas") ; + } + #endif /* RPC_QUOTA */ } *************** *** 333,338 **** --- 369,385 ---- set_effective_uid(0); #if defined(SUNOS5) || defined(_nec_ews) + #if defined(RPC_QUOTA) + if (rpath != NULL) { + /* remote quota */ + DEBUG(5,("disk_quotas: looking for remote quota \"%s:%s\"/uid=%d\n", + rhost, rpath, euser_id)); + ret = disk_quotas_rquota(rhost, rpath, euser_id, bsize, dfree, dsize); + restore_re_uid(); + + return(ret); + } /* else .. local quota */ + #endif /* RPC_QUOTA */ DEBUG(5,("disk_quotas: looking for quotas file \"%s\"\n", name)); if((file=sys_open(name, O_RDONLY,0))<0) { restore_re_uid(); *************** *** 813,815 **** --- 860,1123 ---- } #endif /* VXFS_QUOTA */ + + #if defined(RPC_QUOTA) + /* + * tell to RPC remote quota server for NFS volume + */ + #include + #if defined(SUNOS5) + #include + #endif + #include + + static BOOL disk_quotas_rquota(char *rhost, char *rpath, uid_t euser_id, + SMB_BIG_UINT *bsize, SMB_BIG_UINT *dfree, + SMB_BIG_UINT *dsize) + { + int ret; + struct rquota *rp; + struct getquota_args gq_args; + struct getquota_rslt gq_rslt; + + static int callaurpc(); + + gq_args.gqa_pathp = rpath; + gq_args.gqa_uid = euser_id; + ret = callaurpc(rhost, RQUOTAPROG, RQUOTAVERS, + RQUOTAPROC_GETQUOTA, xdr_getquota_args, (char *)&gq_args, + xdr_getquota_rslt, (char *)&gq_rslt); + + if ( ret != 0) { + DEBUG(5,("disk_quotas_rquota: sunrpc call failed. Error = %s\n", strerror(errno) )); + return(False); + } + switch(gq_rslt.status) { + case Q_OK: + rp = &gq_rslt.getquota_rslt_u.gqr_rquota; + *bsize = rp->rq_bsize; + *dsize = rp->rq_bsoftlimit; + *dfree = (rp->rq_bsoftlimit > rp->rq_curblocks) ? + (rp->rq_bsoftlimit - rp->rq_curblocks) : 0; + DEBUG(5,("disk_quotas_rquota: quota returned for \"%s:%s\" returning bsize %.0f, dfree %.0f, dsize %.0f\n", + rhost,rpath,(double)*bsize,(double)*dfree,(double)*dsize)); + return(True); + case Q_NOQUOTA: + DEBUG(5,("disk_quotas_rquota: noquota for uid\n")); + break; + case Q_EPERM: + DEBUG(5,("disk_quotas_rquota: no permission to access quota\n")); + break; + default: + break; + } + return(False); + } + + static int + callaurpc(host, prognum, versnum, procnum, inproc, in, outproc, out) + char *host; + xdrproc_t inproc, outproc; + char *in, *out; + int prognum, versnum, procnum; + { + struct sockaddr_in server_addr; + enum clnt_stat clnt_stat; + struct hostent *hp; + static struct timeval timeout, tottimeout; + + static CLIENT *client = NULL; + int socket = RPC_ANYSOCK; + + if (client == NULL) { + if ((hp = gethostbyname(host)) == NULL) + return ((int) RPC_UNKNOWNHOST); + timeout.tv_usec = 0; + timeout.tv_sec = 6; + bcopy(hp->h_addr, &server_addr.sin_addr, MIN(hp->h_length,sizeof(server_addr.sin_addr))); + server_addr.sin_family = AF_INET; + server_addr.sin_port = 0; + + if ((client = clntudp_create(&server_addr, prognum, + versnum, timeout, &socket)) == NULL) + + return ((int) rpc_createerr.cf_stat); + + client->cl_auth = authunix_create_default(); + tottimeout.tv_sec = 25; + tottimeout.tv_usec = 0; + } + clnt_stat = clnt_call(client, procnum, inproc, in, + outproc, out, tottimeout); + + return ((int) clnt_stat); + } + + #if defined(SUNOS5) + /* + * As for SUNOS5 the following functions is nonexistent in librpcsvc. + * It may exist in other OS. + * + * (It was generated using rpcgen.) + * #include "rquota.h" + */ + BOOL + xdr_getquota_args(xdrs, objp) + register XDR *xdrs; + getquota_args *objp; + { + + register long *buf; + + if (!xdr_string(xdrs, &objp->gqa_pathp, RQ_PATHLEN)) + return (FALSE); + if (!xdr_int(xdrs, &objp->gqa_uid)) + return (FALSE); + return (TRUE); + } + + BOOL + xdr_rquota(xdrs, objp) + register XDR *xdrs; + rquota *objp; + { + + register long *buf; + + + if (xdrs->x_op == XDR_ENCODE) { + buf = XDR_INLINE(xdrs, 10 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->rq_bsize)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->rq_active)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curblocks)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curfiles)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_btimeleft)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_ftimeleft)) + return (FALSE); + } else { + IXDR_PUT_LONG(buf, objp->rq_bsize); + IXDR_PUT_BOOL(buf, objp->rq_active); + IXDR_PUT_U_LONG(buf, objp->rq_bhardlimit); + IXDR_PUT_U_LONG(buf, objp->rq_bsoftlimit); + IXDR_PUT_U_LONG(buf, objp->rq_curblocks); + IXDR_PUT_U_LONG(buf, objp->rq_fhardlimit); + IXDR_PUT_U_LONG(buf, objp->rq_fsoftlimit); + IXDR_PUT_U_LONG(buf, objp->rq_curfiles); + IXDR_PUT_U_LONG(buf, objp->rq_btimeleft); + IXDR_PUT_U_LONG(buf, objp->rq_ftimeleft); + } + return (TRUE); + } else if (xdrs->x_op == XDR_DECODE) { + buf = XDR_INLINE(xdrs, 10 * BYTES_PER_XDR_UNIT); + if (buf == NULL) { + if (!xdr_int(xdrs, &objp->rq_bsize)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->rq_active)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curblocks)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curfiles)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_btimeleft)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_ftimeleft)) + return (FALSE); + } else { + objp->rq_bsize = IXDR_GET_LONG(buf); + objp->rq_active = IXDR_GET_BOOL(buf); + objp->rq_bhardlimit = IXDR_GET_U_LONG(buf); + objp->rq_bsoftlimit = IXDR_GET_U_LONG(buf); + objp->rq_curblocks = IXDR_GET_U_LONG(buf); + objp->rq_fhardlimit = IXDR_GET_U_LONG(buf); + objp->rq_fsoftlimit = IXDR_GET_U_LONG(buf); + objp->rq_curfiles = IXDR_GET_U_LONG(buf); + objp->rq_btimeleft = IXDR_GET_U_LONG(buf); + objp->rq_ftimeleft = IXDR_GET_U_LONG(buf); + } + return (TRUE); + } + + if (!xdr_int(xdrs, &objp->rq_bsize)) + return (FALSE); + if (!xdr_bool(xdrs, &objp->rq_active)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_bsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curblocks)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fhardlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_fsoftlimit)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_curfiles)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_btimeleft)) + return (FALSE); + if (!xdr_u_int(xdrs, &objp->rq_ftimeleft)) + return (FALSE); + return (TRUE); + } + + BOOL + xdr_gqr_status(xdrs, objp) + register XDR *xdrs; + gqr_status *objp; + { + + register long *buf; + + if (!xdr_enum(xdrs, (enum_t *)objp)) + return (FALSE); + return (TRUE); + } + + BOOL + xdr_getquota_rslt(xdrs, objp) + register XDR *xdrs; + getquota_rslt *objp; + { + + register long *buf; + + if (!xdr_gqr_status(xdrs, &objp->status)) + return (FALSE); + switch (objp->status) { + case Q_OK: + if (!xdr_rquota(xdrs, &objp->getquota_rslt_u.gqr_rquota)) + return (FALSE); + break; + case Q_NOQUOTA: + break; + case Q_EPERM: + break; + default: + return (FALSE); + } + return (TRUE); + } + #endif /* SUNOS5 */ + #endif /* RPC_QUOTA */ -- 'Hiroshi Suzuki' '鈴木 洋'