dovecot-1.2: quota-fs: Added support for NFS group quota.

dovecot at dovecot.org dovecot at dovecot.org
Thu Apr 2 22:03:45 EEST 2009


details:   http://hg.dovecot.org/dovecot-1.2/rev/66a8cbe7f007
changeset: 8892:66a8cbe7f007
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Apr 02 15:02:58 2009 -0400
description:
quota-fs: Added support for NFS group quota.
Based on patch by fandorin at rol.ru.

diffstat:

3 files changed, 261 insertions(+), 11 deletions(-)
src/plugins/quota/Makefile.am |    3 
src/plugins/quota/quota-fs.c  |  130 +++++++++++++++++++++++++++++++++++---
src/plugins/quota/rquota.x    |  139 +++++++++++++++++++++++++++++++++++++++++

diffs (truncated from 331 to 300 lines):

diff -r fbb2343b85d9 -r 66a8cbe7f007 src/plugins/quota/Makefile.am
--- a/src/plugins/quota/Makefile.am	Thu Apr 02 14:25:27 2009 -0400
+++ b/src/plugins/quota/Makefile.am	Thu Apr 02 15:02:58 2009 -0400
@@ -33,7 +33,8 @@ lib10_quota_plugin_la_SOURCES = \
 
 if HAVE_RQUOTA
 RQUOTA_XDR = rquota_xdr.c
-RQUOTA_X = /usr/include/rpcsvc/rquota.x
+#RQUOTA_X = /usr/include/rpcsvc/rquota.x
+RQUOTA_X = rquota.x
 rquota_xdr.c: Makefile $(RQUOTA_X)
 	(echo '#include "lib.h"'; \
 	 echo '#include <rpc/rpc.h>'; \
diff -r fbb2343b85d9 -r 66a8cbe7f007 src/plugins/quota/quota-fs.c
--- a/src/plugins/quota/quota-fs.c	Thu Apr 02 14:25:27 2009 -0400
+++ b/src/plugins/quota/quota-fs.c	Thu Apr 02 15:02:58 2009 -0400
@@ -163,6 +163,15 @@ static struct fs_quota_mountpoint *fs_qu
 #ifdef FS_QUOTA_SOLARIS
 	mount->fd = -1;
 #endif
+
+	if (strcmp(mount->type, "nfs") == 0) {
+		if (strchr(mount->device_path, ':') == NULL) {
+			i_error("quota-fs: %s is not a valid NFS device path",
+				mount->device_path);
+			fs_quota_mountpoint_free(mount);
+			return NULL;
+		}
+	}
 	return mount;
 }
 
@@ -287,9 +296,8 @@ fs_quota_root_get_resources(struct quota
 }
 
 #ifdef HAVE_RQUOTA
-/* retrieve user quota from a remote host */
-static int do_rquota(struct fs_quota_root *root, bool bytes,
-		     uint64_t *value_r, uint64_t *limit_r)
+static int do_rquota_user(struct fs_quota_root *root, bool bytes,
+			  uint64_t *value_r, uint64_t *limit_r)
 {
 	struct getquota_rslt result;
 	struct getquota_args args;
@@ -301,11 +309,7 @@ static int do_rquota(struct fs_quota_roo
 	char *path;
 
 	path = strchr(mount->device_path, ':');
-	if (path == NULL) {
-		i_error("quota-fs: %s is not a valid NFS device path",
-			mount->device_path);
-		return -1;
-	}
+	i_assert(path != NULL);
 
 	host = t_strdup_until(mount->device_path, path);
 	path++;
@@ -353,7 +357,7 @@ static int do_rquota(struct fs_quota_roo
 	switch (result.status) {
 	case Q_OK: {
 		/* convert the results from blocks to bytes */
-		rquota *rq = &result.getquota_rslt_u.gqr_rquota;
+		const rquota *rq = &result.getquota_rslt_u.gqr_rquota;
 
 		if (rq->rq_active) {
 			if (bytes) {
@@ -388,6 +392,110 @@ static int do_rquota(struct fs_quota_roo
 			"from rquota service", result.status);
 		return -1;
 	}
+}
+
+static int do_rquota_group(struct fs_quota_root *root, bool bytes,
+			   uint64_t *value_r, uint64_t *limit_r)
+{
+#ifdef EXT_RQUOTAVERS
+	struct getquota_rslt result;
+	ext_getquota_args args;
+	struct timeval timeout;
+	enum clnt_stat call_status;
+	CLIENT *cl;
+	struct fs_quota_mountpoint *mount = root->mount;
+	const char *host;
+	char *path;
+
+	path = strchr(mount->device_path, ':');
+	i_assert(path != NULL);
+
+	host = t_strdup_until(mount->device_path, path);
+	path++;
+
+	if (root->root.quota->set->debug) {
+		i_info("quota-fs: host=%s, path=%s, gid=%s",
+			host, path, dec2str(root->gid));
+	}
+
+	/* clnt_create() polls for a while to establish a connection */
+	cl = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp");
+	if (cl == NULL) {
+		i_error("quota-fs: could not contact RPC service on %s (group)",
+			host);
+		return -1;
+	}
+
+	/* Establish some RPC credentials */
+	auth_destroy(cl->cl_auth);
+	cl->cl_auth = authunix_create_default();
+
+	/* make the rquota call on the remote host */
+	args.gqa_pathp = path;
+	args.gqa_id = root->gid;
+	args.gqa_type = GRPQUOTA;
+	timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS;
+	timeout.tv_usec = 0;
+
+	call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA,
+				(xdrproc_t)xdr_ext_getquota_args, (char *)&args,
+				(xdrproc_t)xdr_getquota_rslt, (char *)&result,
+				timeout);
+
+	/* the result has been deserialized, let the client go */
+	auth_destroy(cl->cl_auth);
+	clnt_destroy(cl);
+
+	if (call_status != RPC_SUCCESS) {
+		const char *rpc_error_msg = clnt_sperrno(call_status);
+
+		i_error("quota-fs: remote ext rquota call failed: %s",
+			rpc_error_msg);
+		return -1;
+	}
+
+	switch (result.status) {
+	case Q_OK: {
+		/* convert the results from blocks to bytes */
+		const rquota *rq = &result.getquota_rslt_u.gqr_rquota;
+
+		if (rq->rq_active) {
+			if (bytes) {
+				*value_r = (uint64_t)rq->rq_curblocks *
+					(uint64_t)rq->rq_bsize;
+				*limit_r = (uint64_t)rq->rq_bsoftlimit *
+					(uint64_t)rq->rq_bsize;
+			} else {
+				*value_r = rq->rq_curfiles;
+				*limit_r = rq->rq_fsoftlimit;
+			}
+		}
+		if (root->root.quota->set->debug) {
+			i_info("quota-fs: gid=%s, value=%llu, "
+			       "limit=%llu, active=%d", dec2str(root->gid),
+			       (unsigned long long)*value_r,
+			       (unsigned long long)*limit_r, rq->rq_active);
+		}
+		return 1;
+	}
+	case Q_NOQUOTA:
+		if (root->root.quota->set->debug) {
+			i_info("quota-fs: gid=%s, limit=unlimited",
+			       dec2str(root->gid));
+		}
+		return 1;
+	case Q_EPERM:
+		i_error("quota-fs: permission denied to ext rquota service");
+		return -1;
+	default:
+		i_error("quota-fs: unrecognized status code (%d) "
+			"from ext rquota service", result.status);
+		return -1;
+	}
+#else
+	i_error("quota-fs: rquota not compiled with group support");
+	return -1;
+#endif
 }
 #endif
 
@@ -643,7 +751,9 @@ fs_quota_get_resource(struct quota_root 
 #ifdef HAVE_RQUOTA
 	if (strcmp(root->mount->type, "nfs") == 0) {
 		T_BEGIN {
-			ret = do_rquota(root, bytes, value_r, &limit);
+			ret = root->group_disabled ?
+				do_rquota_user(root, bytes, value_r, &limit) :
+				do_rquota_group(root, bytes, value_r, &limit);
 		} T_END;
 	} else
 #endif
diff -r fbb2343b85d9 -r 66a8cbe7f007 src/plugins/quota/rquota.x
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/quota/rquota.x	Thu Apr 02 15:02:58 2009 -0400
@@ -0,0 +1,139 @@
+/* @(#)rquota.x	2.1 88/08/01 4.0 RPCSRC */
+/* @(#)rquota.x 1.2 87/09/20 Copyr 1987 Sun Micro */
+
+/*
+ * Remote quota protocol
+ * Requires unix authentication
+ */
+
+const RQ_PATHLEN = 1024;
+
+struct sq_dqblk {
+	unsigned int rq_bhardlimit;	/* absolute limit on disk blks alloc */
+	unsigned int rq_bsoftlimit;	/* preferred limit on disk blks */
+	unsigned int rq_curblocks;	/* current block count */
+	unsigned int rq_fhardlimit;	/* absolute limit on allocated files */
+	unsigned int rq_fsoftlimit;	/* preferred file limit */
+	unsigned int rq_curfiles;	/* current # allocated files */
+	unsigned int rq_btimeleft;	/* time left for excessive disk use */
+	unsigned int rq_ftimeleft;	/* time left for excessive files */
+};
+
+struct getquota_args {
+	string gqa_pathp<RQ_PATHLEN>;  	/* path to filesystem of interest */
+	int gqa_uid;			/* Inquire about quota for uid */
+};
+
+struct setquota_args {
+	int sqa_qcmd;
+	string sqa_pathp<RQ_PATHLEN>;  	/* path to filesystem of interest */
+	int sqa_id;			/* Set quota for uid */
+	sq_dqblk sqa_dqblk;
+};
+
+struct ext_getquota_args {
+	string gqa_pathp<RQ_PATHLEN>;  	/* path to filesystem of interest */
+	int gqa_type;			/* Type of quota info is needed about */
+	int gqa_id;			/* Inquire about quota for id */
+};
+
+struct ext_setquota_args {
+	int sqa_qcmd;
+	string sqa_pathp<RQ_PATHLEN>;  	/* path to filesystem of interest */
+	int sqa_id;			/* Set quota for id */
+	int sqa_type;			/* Type of quota to set */
+	sq_dqblk sqa_dqblk;
+};
+
+/*
+ * remote quota structure
+ */
+struct rquota {
+	int rq_bsize;			/* block size for block counts */
+	bool rq_active;  		/* indicates whether quota is active */
+	unsigned int rq_bhardlimit;	/* absolute limit on disk blks alloc */
+	unsigned int rq_bsoftlimit;	/* preferred limit on disk blks */
+	unsigned int rq_curblocks;	/* current block count */
+	unsigned int rq_fhardlimit;	/* absolute limit on allocated files */
+	unsigned int rq_fsoftlimit;	/* preferred file limit */
+	unsigned int rq_curfiles;	/* current # allocated files */
+	unsigned int rq_btimeleft;	/* time left for excessive disk use */
+	unsigned int rq_ftimeleft;	/* time left for excessive files */
+};	
+
+enum qr_status {
+	Q_OK = 1,	/* quota returned */
+	Q_NOQUOTA = 2,  /* noquota for uid */
+	Q_EPERM = 3	/* no permission to access quota */
+};
+
+union getquota_rslt switch (qr_status status) {
+case Q_OK:
+	rquota gqr_rquota;	/* valid if status == Q_OK */
+case Q_NOQUOTA:
+	void;
+case Q_EPERM:
+	void;
+};
+
+union setquota_rslt switch (qr_status status) {
+case Q_OK:
+	rquota sqr_rquota;	/* valid if status == Q_OK */
+case Q_NOQUOTA:
+	void;
+case Q_EPERM:
+	void;
+};
+
+program RQUOTAPROG {
+	version RQUOTAVERS {
+		/*
+		 * Get all quotas
+		 */
+		getquota_rslt
+		RQUOTAPROC_GETQUOTA(getquota_args) = 1;
+
+		/*
+	 	 * Get active quotas only
+		 */
+		getquota_rslt
+		RQUOTAPROC_GETACTIVEQUOTA(getquota_args) = 2;
+
+		/*
+		 * Set all quotas
+		 */
+		setquota_rslt
+		RQUOTAPROC_SETQUOTA(setquota_args) = 3;
+
+		/*


More information about the dovecot-cvs mailing list