diff -ruN dovecot-1.1.11.orig/src/plugins/quota/quota-fs.c
dovecot-1.1.11/src/plugins/quota/quota-fs.c
--- dovecot-1.1.11.orig/src/plugins/quota/quota-fs.c 2009-01-06
17:33:51.000000000 +0300
+++ dovecot-1.1.11/src/plugins/quota/quota-fs.c 2009-02-11 12:57:55.000000000
+0300
@@ -288,17 +288,26 @@
#ifdef HAVE_RQUOTA
/* retrieve user quota from a remote host */
-static int do_rquota(struct fs_quota_root *root, bool bytes,
+static int do_rquota(struct fs_quota_root *root, bool group, bool bytes,
uint64_t *value_r, uint64_t *limit_r)
{
- struct getquota_rslt result;
- struct getquota_args args;
- struct timeval timeout;
+ struct getquota_rslt *result;
+ static struct getquota_rslt clnt_res;
enum clnt_stat call_status;
- CLIENT *cl;
+ CLIENT *clnt;
struct fs_quota_mountpoint *mount = root->mount;
const char *host;
char *path;
+ int type, id;
+ struct timeval timeout = { 2, 0 };
+
+ union {
+ getquota_args arg;
+ ext_getquota_args ext_arg;
+ } args;
+
+ type = group ? GRPQUOTA : USRQUOTA;
+ id = group ? root->gid : root->uid;
path = strchr(mount->device_path, ':');
if (path == NULL) {
@@ -311,82 +320,211 @@
path++;
if (getenv("DEBUG") != NULL) {
+ if (group) {
+ i_info("quota-fs: host=%s, path=%s, gid=%s",
+ host, path, dec2str(root->gid));
+ } else {
i_info("quota-fs: host=%s, path=%s, uid=%s",
host, path, dec2str(root->uid));
+ }
}
- /* clnt_create() polls for a while to establish a connection */
- cl = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp");
- if (cl == NULL) {
- i_error("quota-fs: could not contact RPC service on %s",
- 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_uid = root->uid;
-
- timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS;
- timeout.tv_usec = 0;
- call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA,
- (xdrproc_t)xdr_getquota_args, (char *)&args,
- (xdrproc_t)xdr_getquota_rslt, (char *)&result,
- timeout);
+ /*
+ * First try EXT_RQUOTAPROG (Extended (LINUX) RPC quota program)
+ */
+ args.ext_arg.gqa_pathp = path;
+ args.ext_arg.gqa_id = id;
+ args.ext_arg.gqa_type = type;
- /* 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);
-
+ /*
+ * Create a RPC client.
+ */
+
+ if ((clnt = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp")) !=
NULL) {
+ /*
+ * Initialize unix authentication
+ */
+ clnt->cl_auth = authunix_create_default();
+
+ /*
+ * Setup protocol timeout.
+ */
+ clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout);
+
+ /*
+ * Do RPC call and check result.
+ */
+
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ call_status = clnt_call (clnt, RQUOTAPROC_GETQUOTA,
+ (xdrproc_t) xdr_ext_getquota_args,
(caddr_t) &args.ext_arg,
+ (xdrproc_t) xdr_getquota_rslt, (caddr_t)
&clnt_res,
+ timeout);
+ result = &clnt_res;
+ /*
+ * Destroy unix authentication and RPC client structure.
+ */
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+
+ if (call_status != RPC_SUCCESS) {
+ const char *rpc_error_msg = clnt_sperrno(call_status);
i_error("quota-fs: remote rquota call failed: %s",
rpc_error_msg);
return -1;
- }
-
- switch (result.status) {
- case Q_OK: {
+ }
+
+ switch (result->status) {
+ case Q_OK: {
/* convert the results from blocks to bytes */
- rquota *rq = &result.getquota_rslt_u.gqr_rquota;
+ 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 (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 (getenv("DEBUG") != NULL) {
+ if (group) {
+ 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);
+ } else {
i_info("quota-fs: uid=%s, value=%llu, "
"limit=%llu, active=%d", dec2str(root->uid),
(unsigned long long)*value_r,
(unsigned long long)*limit_r, rq->rq_active);
+ }
}
return 1;
- }
- case Q_NOQUOTA:
+ }
+ case Q_NOQUOTA:
if (getenv("DEBUG") != NULL) {
+ if (group) {
+ i_info("quota-fs: gid=%s, limit=unlimited",
+ dec2str(root->gid));
+ } else {
i_info("quota-fs: uid=%s, limit=unlimited",
dec2str(root->uid));
+ }
}
return 1;
- case Q_EPERM:
+ case Q_EPERM:
i_error("quota-fs: permission denied to rquota service");
return -1;
- default:
+ default:
i_error("quota-fs: unrecognized status code (%d) "
- "from rquota service", result.status);
+ "from rquota service", result->status);
return -1;
+ }
+ } else {
+ result = NULL;
+ }
+
+ if (result == NULL || !result->status) {
+ if (type == USRQUOTA) {
+ /*
+ * Try RQUOTAPROG because server doesn't seem to understand
EXT_RQUOTAPROG. (NON-LINUX servers.)
+ */
+ args.arg.gqa_pathp = path;
+ args.arg.gqa_uid = id;
+
+ /*
+ * Create a RPC client.
+ */
+ if ((clnt = clnt_create(host, RQUOTAPROG, RQUOTAVERS,
"udp")) != NULL) {
+ /*
+ * Initialize unix authentication
+ */
+ clnt->cl_auth = authunix_create_default();
+
+ /*
+ * Setup protocol timeout.
+ */
+ clnt_control(clnt, CLSET_TIMEOUT, (caddr_t) & timeout);
+
+ /*
+ * Do RPC call and check result.
+ */
+ memset((char *)&clnt_res, 0, sizeof(clnt_res));
+ call_status = clnt_call (clnt, RQUOTAPROC_GETQUOTA,
+ (xdrproc_t) xdr_getquota_args,
(caddr_t) &args.arg,
+ (xdrproc_t) xdr_getquota_rslt,
(caddr_t) &clnt_res,
+ timeout);
+ result = &clnt_res;
+ /*
+ * Destroy unix authentication and RPC client structure.
+ */
+ auth_destroy(clnt->cl_auth);
+ clnt_destroy(clnt);
+
+ if (call_status != RPC_SUCCESS) {
+ const char *rpc_error_msg =
clnt_sperrno(call_status);
+ i_error("quota-fs: remote rquota call failed: %s",
+ rpc_error_msg);
+ return -1;
+ }
+
+ switch (result->status) {
+ case Q_OK: {
+ /* convert the results from blocks to bytes */
+ 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 (getenv("DEBUG") != NULL) {
+ if (group) {
+ 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);
+ } else {
+ i_info("quota-fs: uid=%s, value=%llu, "
+ "limit=%llu, active=%d",
dec2str(root->uid),
+ (unsigned long long)*value_r,
+ (unsigned long long)*limit_r,
rq->rq_active);
+ }
+ }
+ return 1;
+ }
+ case Q_NOQUOTA:
+ if (getenv("DEBUG") != NULL) {
+ if (group) {
+ i_info("quota-fs: gid=%s, limit=unlimited",
+ dec2str(root->gid));
+ } else {
+ i_info("quota-fs: uid=%s, limit=unlimited",
+ dec2str(root->uid));
+ }
+ }
+ return 1;
+ case Q_EPERM:
+ i_error("quota-fs: permission denied to rquota
service");
+ return -1;
+ default:
+ i_error("quota-fs: unrecognized status code (%d) "
+ "from rquota service", result->status);
+ return -1;
+ }
+
+ }
+ }
}
}
#endif
@@ -602,6 +740,7 @@
uint64_t limit = 0;
bool bytes;
int ret;
+ bool group;
*value_r = 0;
@@ -614,7 +753,12 @@
#ifdef HAVE_RQUOTA
if (strcmp(root->mount->type, "nfs") == 0) {
T_BEGIN {
- ret = do_rquota(root, bytes, value_r, &limit);
+ if (root->group_disabled){
+ group = FALSE;
+ } else {
+ group = TRUE;
+ }
+ ret = do_rquota(root, group, bytes, value_r, &limit);
} T_END;
} else
#endif
Hi all. Unfortunately, the existing quota-fs does not know how to get
GROUP quota with NFS storage. But there is a tool for Linux quota-tools
(http://slackware.rol.ru/slackware/slackware-12.2/source/a/quota/). This
patch is made on the basis quota-tools. The patch was successful alpha
testing. Suggestions and comments are welcome.
- [Dovecot] quota-fs: get nfs GROUP quota (patch) [email protected]
