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.
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

Reply via email to