Module Name:    src
Committed By:   dholland
Date:           Mon Jan  9 15:29:56 UTC 2012

Modified Files:
        src/lib/libquota: Makefile quota_get.c quota_open.c quotapvt.h
Added Files:
        src/lib/libquota: quota_nfs.c

Log Message:
Add quota_nfs.c and implement quota_get() for nfs, using
code from getnfsquota().

Also implement quota_getmountdevice().


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/lib/libquota/Makefile
cvs rdiff -u -r1.2 -r1.3 src/lib/libquota/quota_get.c \
    src/lib/libquota/quota_open.c
cvs rdiff -u -r0 -r1.1 src/lib/libquota/quota_nfs.c
cvs rdiff -u -r1.1 -r1.2 src/lib/libquota/quotapvt.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libquota/Makefile
diff -u src/lib/libquota/Makefile:1.3 src/lib/libquota/Makefile:1.4
--- src/lib/libquota/Makefile:1.3	Mon Jan  9 15:27:04 2012
+++ src/lib/libquota/Makefile	Mon Jan  9 15:29:55 2012
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.3 2012/01/09 15:27:04 dholland Exp $
+#	$NetBSD: Makefile,v 1.4 2012/01/09 15:29:55 dholland Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/4/93
 
 .include <bsd.own.mk>
@@ -19,5 +19,6 @@ SRCS+=	quota_schema.c
 SRCS+=	quota_get.c quota_put.c quota_delete.c
 SRCS+=	quota_cursor.c
 SRCS+=	quota_proplib.c
+SRCS+=	quota_nfs.c
 
 .include <bsd.lib.mk>

Index: src/lib/libquota/quota_get.c
diff -u src/lib/libquota/quota_get.c:1.2 src/lib/libquota/quota_get.c:1.3
--- src/lib/libquota/quota_get.c:1.2	Mon Jan  9 15:27:04 2012
+++ src/lib/libquota/quota_get.c	Mon Jan  9 15:29:55 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota_get.c,v 1.2 2012/01/09 15:27:04 dholland Exp $	*/
+/*	$NetBSD: quota_get.c,v 1.3 2012/01/09 15:29:55 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,7 +29,7 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: quota_get.c,v 1.2 2012/01/09 15:27:04 dholland Exp $");
+__RCSID("$NetBSD: quota_get.c,v 1.3 2012/01/09 15:29:55 dholland Exp $");
 
 #include <quota.h>
 #include "quotapvt.h"
@@ -47,5 +47,9 @@ quotaval_clear(struct quotaval *qv)
 int
 quota_get(struct quotahandle *qh, const struct quotakey *qk, struct quotaval *qv)
 {
-	return __quota_proplib_get(qh, qk, qv);
+	if (qh->qh_isnfs) {
+		return __quota_nfs_get(qh, qk, qv);
+	} else {
+		return __quota_proplib_get(qh, qk, qv);
+	}
 }
Index: src/lib/libquota/quota_open.c
diff -u src/lib/libquota/quota_open.c:1.2 src/lib/libquota/quota_open.c:1.3
--- src/lib/libquota/quota_open.c:1.2	Mon Jan  9 15:27:04 2012
+++ src/lib/libquota/quota_open.c	Mon Jan  9 15:29:56 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quota_open.c,v 1.2 2012/01/09 15:27:04 dholland Exp $	*/
+/*	$NetBSD: quota_open.c,v 1.3 2012/01/09 15:29:56 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -29,8 +29,10 @@
  */
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: quota_open.c,v 1.2 2012/01/09 15:27:04 dholland Exp $");
+__RCSID("$NetBSD: quota_open.c,v 1.3 2012/01/09 15:29:56 dholland Exp $");
 
+#include <sys/types.h>
+#include <sys/statvfs.h>
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
@@ -41,20 +43,64 @@ __RCSID("$NetBSD: quota_open.c,v 1.2 201
 struct quotahandle *
 quota_open(const char *path)
 {
+
+	struct statvfs stv;
 	struct quotahandle *qh;
+	int isnfs;
 	int serrno;
 
+	if (statvfs(path, &stv) < 0) {
+		return NULL;
+	}
+
+	/*
+	 * We need to know up front if the volume is NFS. If so, we
+	 * don't go to the kernel at all but instead do RPCs to the
+	 * NFS server's rpc.rquotad. Therefore, don't check the
+	 * mount flags for quota support or do anything else that
+	 * reaches the kernel.
+	 */
+	
+	if (!strcmp(stv.f_fstypename, "nfs")) {
+		isnfs = 1;
+	} else {
+		isnfs = 0;
+		if ((stv.f_flag & ST_QUOTA) == 0) {
+			/* XXX: correct errno? */
+			errno = EOPNOTSUPP;
+			return NULL;
+		}
+	}
+
 	qh = malloc(sizeof(*qh));
 	if (qh == NULL) {
 		return NULL;
 	}
-	qh->qh_mountpoint = strdup(path);
+
+	/*
+	 * Get the mount point from statvfs; this way the passed-in
+	 * path can be any path on the volume.
+	 */
+
+	qh->qh_mountpoint = strdup(stv.f_mntonname);
 	if (qh->qh_mountpoint == NULL) {
 		serrno = errno;
 		free(qh);
 		errno = serrno;
 		return NULL;
 	}
+
+	qh->qh_mountdevice = strdup(stv.f_mntfromname);
+	if (qh->qh_mountdevice == NULL) {
+		serrno = errno;
+		free(qh->qh_mountpoint);
+		free(qh);
+		errno = serrno;
+		return NULL;
+	}
+
+	qh->qh_isnfs = isnfs;
+
 	return qh;
 }
 
@@ -67,13 +113,13 @@ quota_getmountpoint(struct quotahandle *
 const char *
 quota_getmountdevice(struct quotahandle *qh)
 {
-	errno = ENOSYS;
-	return NULL;
+	return qh->qh_mountdevice;
 }
 
 void
 quota_close(struct quotahandle *qh)
 {
+	free(qh->qh_mountdevice);
 	free(qh->qh_mountpoint);
 	free(qh);
 }

Index: src/lib/libquota/quotapvt.h
diff -u src/lib/libquota/quotapvt.h:1.1 src/lib/libquota/quotapvt.h:1.2
--- src/lib/libquota/quotapvt.h:1.1	Mon Jan  9 15:27:04 2012
+++ src/lib/libquota/quotapvt.h	Mon Jan  9 15:29:56 2012
@@ -1,4 +1,4 @@
-/*	$NetBSD: quotapvt.h,v 1.1 2012/01/09 15:27:04 dholland Exp $	*/
+/*	$NetBSD: quotapvt.h,v 1.2 2012/01/09 15:29:56 dholland Exp $	*/
 /*-
  * Copyright (c) 2011 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -30,8 +30,16 @@
 
 struct quotahandle {
 	char *qh_mountpoint;
+	char *qh_mountdevice;
+	int qh_isnfs;
+	char spare[14*sizeof(char *) + 15 * sizeof(int)];
 };
 
 /* proplib kernel interface */
 int __quota_proplib_get(struct quotahandle *qh, const struct quotakey *qk,
 			struct quotaval *qv);
+
+/* nfs rquotad interface */
+int __quota_nfs_get(struct quotahandle *qh, const struct quotakey *qk,
+		    struct quotaval *qv);
+

Added files:

Index: src/lib/libquota/quota_nfs.c
diff -u /dev/null src/lib/libquota/quota_nfs.c:1.1
--- /dev/null	Mon Jan  9 15:29:56 2012
+++ src/lib/libquota/quota_nfs.c	Mon Jan  9 15:29:56 2012
@@ -0,0 +1,222 @@
+/*	$NetBSD: quota_nfs.c,v 1.1 2012/01/09 15:29:56 dholland Exp $	*/
+/*-
+  * Copyright (c) 2011 Manuel Bouyer
+  * All rights reserved.
+  *
+  * Redistribution and use in source and binary forms, with or without
+  * modification, are permitted provided that the following conditions
+  * are met:
+  * 1. Redistributions of source code must retain the above copyright
+  *    notice, this list of conditions and the following disclaimer.
+  * 2. Redistributions in binary form must reproduce the above copyright
+  *    notice, this list of conditions and the following disclaimer in the
+  *    documentation and/or other materials provided with the distribution.
+  *
+  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+  * POSSIBILITY OF SUCH DAMAGE.
+  */
+
+#include <sys/cdefs.h>
+__RCSID("$NetBSD: quota_nfs.c,v 1.1 2012/01/09 15:29:56 dholland Exp $");
+
+#include <sys/types.h>
+#include <sys/param.h> /* XXX for DEV_BSIZE */
+#include <stdlib.h>
+#include <string.h>
+#include <limits.h>
+#include <netdb.h>
+#include <errno.h>
+
+#include <rpc/rpc.h>
+#include <rpc/pmap_prot.h>
+#include <rpcsvc/rquota.h>
+
+#include <quota.h>
+#include "quotapvt.h"
+
+static uint64_t
+rq_scale(uint32_t rqblocks, uint32_t rqsize)
+{
+	return ((uint64_t)rqblocks * rqsize) / DEV_BSIZE;
+}
+
+static uint64_t
+rq_scalelimit(uint32_t rqval, uint32_t rqsize)
+{
+	if (rqval == 0) {
+		return QUOTA_NOLIMIT;
+	} else {
+		return rq_scale(rqval - 1, rqsize);
+	}
+}
+
+static uint64_t
+rq_plainlimit(uint32_t rqval)
+{
+	if (rqval == 0) {
+		return QUOTA_NOLIMIT;
+	} else {
+		return rqval - 1;
+	}
+}
+
+static void
+rquota_to_quotavals(const struct rquota *rq,
+		    struct quotaval *blocks, struct quotaval *files)
+{
+	struct timeval now;
+
+	gettimeofday(&now, NULL);
+
+	/* blocks*/
+	blocks->qv_hardlimit = rq_scalelimit(rq->rq_bhardlimit, rq->rq_bsize);
+	blocks->qv_softlimit = rq_scalelimit(rq->rq_bsoftlimit, rq->rq_bsize);
+	blocks->qv_usage = rq_scale(rq->rq_curblocks, rq->rq_bsize);
+	blocks->qv_expiretime = rq->rq_btimeleft + now.tv_sec;
+	blocks->qv_grace = QUOTA_NOTIME;
+
+	/* inodes */
+	files->qv_hardlimit = rq_plainlimit(rq->rq_fhardlimit);
+	files->qv_softlimit = rq_plainlimit(rq->rq_fsoftlimit);
+	files->qv_usage = rq->rq_curfiles;
+	files->qv_expiretime = rq->rq_ftimeleft + now.tv_sec;
+	files->qv_grace = QUOTA_NOTIME;
+}
+ 
+static int
+callaurpc(const char *host, rpcprog_t prognum, rpcvers_t versnum,
+    rpcproc_t procnum, xdrproc_t inproc, void *in, xdrproc_t outproc, void *out)
+{
+	struct sockaddr_in server_addr;
+	enum clnt_stat clnt_stat;
+	struct hostent *hp;
+	struct timeval timeout, tottimeout;
+ 
+	CLIENT *client = NULL;
+	int sock = RPC_ANYSOCK;
+ 
+	if ((hp = gethostbyname(host)) == NULL)
+		return (int) RPC_UNKNOWNHOST;
+	timeout.tv_usec = 0;
+	timeout.tv_sec = 6;
+	memmove(&server_addr.sin_addr, hp->h_addr, hp->h_length);
+	server_addr.sin_family = AF_INET;
+	server_addr.sin_port =  0;
+
+	if ((client = clntudp_create(&server_addr, prognum,
+	    versnum, timeout, &sock)) == 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;
+}
+
+int
+__quota_nfs_get(struct quotahandle *qh, const struct quotakey *qk,
+		struct quotaval *qv)
+{
+	struct getquota_args gq_args;
+	struct ext_getquota_args ext_gq_args;
+	struct getquota_rslt gq_rslt;
+	struct quotaval blocks, inodes;
+	char *host, *path;
+	int ret, rpcqtype;
+	int sverrno;
+
+	switch (qk->qk_idtype) {
+	    case QUOTA_IDTYPE_USER:
+		rpcqtype = RQUOTA_USRQUOTA;
+		break;
+	    case QUOTA_IDTYPE_GROUP:
+		rpcqtype = RQUOTA_GRPQUOTA;
+		break;
+	    default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	switch (qk->qk_objtype) {
+	    case QUOTA_OBJTYPE_BLOCKS:
+	    case QUOTA_OBJTYPE_FILES:
+		break;
+	    default:
+		errno = EINVAL;
+		return -1;
+	}
+
+	/*
+	 * must be some form of "hostname:/path"
+	 */
+	path = strdup(qh->qh_mountdevice);
+	if (path == NULL) {
+		errno = ENOMEM;
+		return -1;
+	}
+	host = strsep(&path, ":");
+	if (path == NULL) {
+		free(host);
+		errno = EINVAL;
+		return -1;
+	}
+
+	ext_gq_args.gqa_pathp = path;
+	ext_gq_args.gqa_id = qk->qk_id;
+	ext_gq_args.gqa_type = rpcqtype;
+	ret = callaurpc(host, RQUOTAPROG, EXT_RQUOTAVERS,
+	    RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_ext_getquota_args,
+	    &ext_gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt);
+	if (ret == RPC_PROGVERSMISMATCH && rpcqtype == RQUOTA_USRQUOTA) {
+		/* try RQUOTAVERS */
+		gq_args.gqa_pathp = path;
+		gq_args.gqa_uid = qk->qk_id;
+		ret = callaurpc(host, RQUOTAPROG, RQUOTAVERS,
+		    RQUOTAPROC_GETQUOTA, (xdrproc_t)xdr_getquota_args,
+		    &gq_args, (xdrproc_t)xdr_getquota_rslt, &gq_rslt);
+	}
+	sverrno = errno;
+	free(host);
+
+	if (ret != RPC_SUCCESS) {
+		errno = sverrno;
+		return -1;
+	}
+
+	switch (gq_rslt.status) {
+	case Q_NOQUOTA:
+		quotaval_clear(qv);
+		return 0;
+		break;
+	case Q_EPERM:
+		errno = EACCES;
+		return -1;
+	case Q_OK:
+		rquota_to_quotavals(&gq_rslt.getquota_rslt_u.gqr_rquota,
+				    &blocks, &inodes);
+		if (qk->qk_objtype == QUOTA_OBJTYPE_BLOCKS) {
+			*qv = blocks;
+		} else {
+			*qv = inodes;
+		}
+		return 0;
+	default:
+		break;
+	}
+	/* XXX not exactly a good errno */
+	errno = ERANGE;
+	return -1;
+}
+

Reply via email to