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