I posted some code on June 12 that can support v2 quota on systems that don't have headers for it. On Fri, 2006-06-23 at 15:36 +0900, Alan Premselaar wrote:
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
Scott,
Do you know if this will address issues with v2 quota support on RHEL 3 using ext3 filesystems?
alan
Scott Alter wrote:
Apparently, there is still a bug - for the group support to work, the user name and the group name must currently be the same.
Sorry for all of the emails, but I just fixed this bug. It should really work now. Attached are quota-fs.c and the working patch to the latest CVS version. Please let me know if you have any problems.
-Scott
------------------------------------------------------------------------
--- quota-fs.c.xfs 2006-06-23 01:36:55.000000000 -0400 +++ quota-fs.c 2006-06-23 01:39:26.000000000 -0400 @@ -41,6 +41,7 @@ struct quota_root root;
uid_t uid; + gid_t gid; struct fs_quota_mountpoint *mount; };
@@ -61,6 +62,7 @@ root->root.name = i_strdup(name); root->root.v = quota_backend_fs.v; root->uid = geteuid(); + root->gid = getegid();
return &root->root; } @@ -166,7 +168,11 @@ static const char *const * fs_quota_root_get_resources(struct quota_root *root __attr_unused__) { - static const char *resources[] = { QUOTA_NAME_STORAGE, NULL }; + static const char *resources[] = { + QUOTA_NAME_STORAGE, + QUOTA_NAME_MESSAGES, + NULL + };
return resources; } @@ -180,72 +186,100 @@ #ifdef HAVE_Q_QUOTACTL struct quotctl ctl; #endif + int value_r_t, limit_r_t, value_r_c=0, limit_r_c=0; + char args[] = {USRQUOTA , GRPQUOTA}; + int what[] = {root->uid, root->gid}; + short i;
*value_r = 0; *limit_r = 0;
- if (strcasecmp(name, QUOTA_NAME_STORAGE) != 0 || root->mount == NULL) + if (root->mount == NULL) return 0;
+ + for (i = 0; i < 2; i++) { + #if defined (HAVE_QUOTACTL) && defined(HAVE_SYS_QUOTA_H) - /* Linux */ + /* Linux */ #ifdef HAVE_LINUX_DQBLK_XFS_H - if (strcmp(root->mount->type, "xfs") == 0) { - /* XFS */ - struct fs_disk_quota xdqblk; + if (strcmp(root->mount->type, "xfs") == 0) { + /* XFS */ + struct fs_disk_quota xdqblk;
- if (quotactl(QCMD(Q_XGETQUOTA, USRQUOTA), - root->mount->device_path, - root->uid, (void *)&xdqblk) < 0) { - i_error("quotactl(Q_XGETQUOTA, %s) failed: %m", - root->mount->device_path); - quota_set_error(_root->setup->quota, - "Internal quota error"); - return -1; - } - dqblk.dqb_curblocks = xdqblk.d_bcount << 9; - dqblk.dqb_bsoftlimit = xdqblk.d_blk_softlimit >> 1; - } else + if (quotactl(QCMD(Q_XGETQUOTA, args[i]), + root->mount->device_path, + what[i], (void *)&xdqblk) < 0) { + i_error("quotactl(Q_XGETQUOTA, %s) failed: %m", + root->mount->device_path); + quota_set_error(_root->setup->quota, + "Internal quota error"); + return -1; + } + dqblk.dqb_curblocks = xdqblk.d_bcount << 9; + dqblk.dqb_curinodes = xdqblk.d_icount << 9; + dqblk.dqb_bsoftlimit = xdqblk.d_blk_softlimit >> 1; + dqblk.dqb_isoftlimit = xdqblk.d_ino_softlimit >> 1; + } else #endif - { - /* ext2, ext3 */ - if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), - root->mount->device_path, - root->uid, (void *)&dqblk) < 0) { + { + /* ext2, ext3 */ + if (quotactl(QCMD(Q_GETQUOTA, args[i]), + root->mount->device_path, + what[i], (void *)&dqblk) < 0) { + i_error("quotactl(Q_GETQUOTA, %s) failed: %m", + root->mount->device_path); + quota_set_error(_root->setup->quota, + "Internal quota error"); + return -1; + } + } +#elif defined(HAVE_QUOTACTL) + /* BSD, AIX */ + if (quotactl(root->mount->device_path, QCMD(Q_GETQUOTA, args[i]), + what[i], (void *)&dqblk) < 0) { i_error("quotactl(Q_GETQUOTA, %s) failed: %m", root->mount->device_path); - quota_set_error(_root->setup->quota, - "Internal quota error"); + quota_set_error(_root->setup->quota, "Internal quota error"); return -1; } - } -#elif defined(HAVE_QUOTACTL) - /* BSD, AIX */ - if (quotactl(root->mount->device_path, QCMD(Q_GETQUOTA, USRQUOTA), - root->uid, (void *)&dqblk) < 0) { - i_error("quotactl(Q_GETQUOTA, %s) failed: %m", - root->mount->device_path); - quota_set_error(_root->setup->quota, "Internal quota error"); - return -1; - } #else - /* Solaris */ - if (root->mount->fd == -1) - return 0; + /* Solaris */ + if (root->mount->fd == -1) + return 0;
- ctl.op = Q_GETQUOTA; - ctl.uid = root->uid; - ctl.addr = (caddr_t)&dqblk; - if (ioctl(root->mount->fd, Q_QUOTACTL, &ctl) < 0) { - i_error("ioctl(%s, Q_QUOTACTL) failed: %m", root->mount->path); - quota_set_error(_root->setup->quota, "Internal quota error"); - return -1; - } + ctl.op = Q_GETQUOTA; + ctl.uid = root->uid; + ctl.addr = (caddr_t)&dqblk; + if (ioctl(root->mount->fd, Q_QUOTACTL, &ctl) < 0) { + i_error("ioctl(%s, Q_QUOTACTL) failed: %m", root->mount->path); + quota_set_error(_root->setup->quota, "Internal quota error"); + return -1; + } #endif - *value_r = (uint64_t)dqblk.dqb_curblocks * - (uint64_t)root->mount->blk_size / 1024; - *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * - (uint64_t)root->mount->blk_size / 1024; + if (strcmp(name, QUOTA_NAME_STORAGE) == 0) { + value_r_t = (uint64_t)dqblk.dqb_curblocks * + (uint64_t)root->mount->blk_size / 1024 / 4096; + limit_r_t = (uint64_t)dqblk.dqb_bsoftlimit * + (uint64_t)root->mount->blk_size / 1024 / 4; + } else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0) { + value_r_t = (uint64_t)dqblk.dqb_curinodes; + limit_r_t = (uint64_t)dqblk.dqb_isoftlimit; + } else { + return 0; + } + + if ((limit_r_c == 0 && limit_r_t >= 0) || + (limit_r_t - value_r_t) < (limit_r_c - value_r_c)) { + limit_r_c = limit_r_t; + value_r_c = value_r_t; + } + + } + + *limit_r = limit_r_c; + *value_r = value_r_c; + return 1; }
------------------------------------------------------------------------
/* Copyright (C) 2005-2006 Timo Sirainen */
/* Only for reporting filesystem quota */
#include "lib.h" #include "array.h" #include "str.h" #include "mountpoint.h" #include "quota-private.h" #include "quota-fs.h"
#ifdef HAVE_FS_QUOTA
#include
#include #include #include #include #ifdef HAVE_LINUX_DQBLK_XFS_H # include #endif #ifdef HAVE_STRUCT_DQBLK_CURSPACE # define dqb_curblocks dqb_curspace #endif
struct fs_quota_mountpoint { char *mount_path; char *device_path; char *type;
unsigned int blk_size;
#ifdef HAVE_Q_QUOTACTL int fd; char *path; #endif };
struct fs_quota_root { struct quota_root root;
uid_t uid; gid_t gid; struct fs_quota_mountpoint *mount; };
struct fs_quota_root_iter { struct quota_root_iter iter;
bool sent; };
extern struct quota_backend quota_backend_fs;
static struct quota_root * fs_quota_init(struct quota_setup *setup __attr_unused__, const char *name) { struct fs_quota_root *root;
root = i_new(struct fs_quota_root, 1); root->root.name = i_strdup(name); root->root.v = quota_backend_fs.v; root->uid = geteuid(); root->gid = getegid();
return &root->root; }
static void fs_quota_mountpoint_free(struct fs_quota_mountpoint *mount) { #ifdef HAVE_Q_QUOTACTL if (mount->fd != -1) { if (close(mount->fd) < 0) i_error("close(%s) failed: %m", mount->path); } i_free(mount->path); #endif
i_free(mount->device_path); i_free(mount->mount_path); i_free(mount->type); i_free(mount); }
static void fs_quota_deinit(struct quota_root *_root) { struct fs_quota_root *root = (struct fs_quota_root *)_root;
if (root->mount != NULL) fs_quota_mountpoint_free(root->mount); i_free(root->root.name); i_free(root); }
static struct fs_quota_mountpoint *fs_quota_mountpoint_get(const char *dir) { struct fs_quota_mountpoint *mount; struct mountpoint point; int ret;
ret = mountpoint_get(dir, default_pool, &point); if (ret <= 0) return NULL;
mount = i_new(struct fs_quota_mountpoint, 1); mount->blk_size = point.block_size; mount->device_path = point.device_path; mount->mount_path = point.mount_path; mount->type = point.type; return mount; }
static bool fs_quota_add_storage(struct quota_root *_root, struct mail_storage *storage) { struct fs_quota_root *root = (struct fs_quota_root *)_root; struct fs_quota_mountpoint *mount; const char *dir; bool is_file;
dir = mail_storage_get_mailbox_path(storage, "", &is_file);
if (getenv("DEBUG") != NULL) i_info("fs quota add storage dir = %s", dir);
mount = fs_quota_mountpoint_get(dir); if (root->mount == NULL) { if (mount == NULL) { /* Not found */ return TRUE; } root->mount = mount; } else { bool match = strcmp(root->mount->mount_path, mount->mount_path) == 0;
fs_quota_mountpoint_free(mount); if (!match) { /* different mountpoints, can't use this */ return FALSE; } mount = root->mount; }
if (getenv("DEBUG") != NULL) { i_info("fs quota block device = %s", mount->device_path); i_info("fs quota mount point = %s", mount->mount_path); }
#ifdef HAVE_Q_QUOTACTL if (mount->path == NULL) { mount->path = i_strconcat(mount->mount_path, "/quotas", NULL); mount->fd = open(mount->path, O_RDONLY); if (mount->fd == -1 && errno != ENOENT) i_error("open(%s) failed: %m", mount->path); } #endif return TRUE; }
static void fs_quota_remove_storage(struct quota_root *root __attr_unused__, struct mail_storage *storage __attr_unused__) { }
static const char *const * fs_quota_root_get_resources(struct quota_root *root __attr_unused__) { static const char *resources[] = { QUOTA_NAME_STORAGE, QUOTA_NAME_MESSAGES, NULL };
return resources; }
static int fs_quota_get_resource(struct quota_root *_root, const char *name, uint64_t *value_r, uint64_t *limit_r) { struct fs_quota_root *root = (struct fs_quota_root *)_root; struct dqblk dqblk; #ifdef HAVE_Q_QUOTACTL struct quotctl ctl; #endif int value_r_t, limit_r_t, value_r_c=0, limit_r_c=0; char args[] = {USRQUOTA , GRPQUOTA}; int what[] = {root->uid, root->gid}; short i;
*value_r = 0; *limit_r = 0;
if (root->mount == NULL) return 0;
for (i = 0; i < 2; i++) {
#if defined (HAVE_QUOTACTL) && defined(HAVE_SYS_QUOTA_H) /* Linux */ #ifdef HAVE_LINUX_DQBLK_XFS_H if (strcmp(root->mount->type, "xfs") == 0) { /* XFS */ struct fs_disk_quota xdqblk;
if (quotactl(QCMD(Q_XGETQUOTA, args[i]), root->mount->device_path, what[i], (void *)&xdqblk) < 0) { i_error("quotactl(Q_XGETQUOTA, %s) failed: %m", root->mount->device_path); quota_set_error(_root->setup->quota, "Internal quota error"); return -1; } dqblk.dqb_curblocks = xdqblk.d_bcount << 9; dqblk.dqb_curinodes = xdqblk.d_icount << 9; dqblk.dqb_bsoftlimit = xdqblk.d_blk_softlimit >> 1; dqblk.dqb_isoftlimit = xdqblk.d_ino_softlimit >> 1; } else #endif { /* ext2, ext3 */ if (quotactl(QCMD(Q_GETQUOTA, args[i]), root->mount->device_path, what[i], (void *)&dqblk) < 0) { i_error("quotactl(Q_GETQUOTA, %s) failed: %m", root->mount->device_path); quota_set_error(_root->setup->quota, "Internal quota error"); return -1; } } #elif defined(HAVE_QUOTACTL) /* BSD, AIX */ if (quotactl(root->mount->device_path, QCMD(Q_GETQUOTA, args[i]), what[i], (void *)&dqblk) < 0) { i_error("quotactl(Q_GETQUOTA, %s) failed: %m", root->mount->device_path); quota_set_error(_root->setup->quota, "Internal quota error"); return -1; } #else /* Solaris */ if (root->mount->fd == -1) return 0;
ctl.op = Q_GETQUOTA; ctl.uid = root->uid; ctl.addr = (caddr_t)&dqblk; if (ioctl(root->mount->fd, Q_QUOTACTL, &ctl) < 0) { i_error("ioctl(%s, Q_QUOTACTL) failed: %m", root->mount->path); quota_set_error(_root->setup->quota, "Internal quota error"); return -1; } #endif if (strcmp(name, QUOTA_NAME_STORAGE) == 0) { value_r_t = (uint64_t)dqblk.dqb_curblocks * (uint64_t)root->mount->blk_size / 1024 / 4096; limit_r_t = (uint64_t)dqblk.dqb_bsoftlimit * (uint64_t)root->mount->blk_size / 1024 / 4; } else if (strcmp(name, QUOTA_NAME_MESSAGES) == 0) { value_r_t = (uint64_t)dqblk.dqb_curinodes; limit_r_t = (uint64_t)dqblk.dqb_isoftlimit; } else { return 0; }
if ((limit_r_c == 0 && limit_r_t >= 0) || (limit_r_t - value_r_t) < (limit_r_c - value_r_c)) { limit_r_c = limit_r_t; value_r_c = value_r_t; }
}
*limit_r = limit_r_c; *value_r = value_r_c;
return 1; }
static int fs_quota_set_resource(struct quota_root *root, const char *name __attr_unused__, uint64_t value __attr_unused__) { quota_set_error(root->setup->quota, MAIL_STORAGE_ERR_NO_PERMISSION); return -1; }
static struct quota_root_transaction_context * fs_quota_transaction_begin(struct quota_root *root, struct quota_transaction_context *ctx) { struct quota_root_transaction_context *root_ctx;
root_ctx = i_new(struct quota_root_transaction_context, 1); root_ctx->root = root; root_ctx->ctx = ctx; root_ctx->disabled = TRUE; return root_ctx; }
static int fs_quota_transaction_commit(struct quota_root_transaction_context *ctx) { i_free(ctx); return 0; }
struct quota_backend quota_backend_fs = { "fs",
{ fs_quota_init, fs_quota_deinit,
fs_quota_add_storage, fs_quota_remove_storage,
fs_quota_root_get_resources,
fs_quota_get_resource, fs_quota_set_resource,
fs_quota_transaction_begin, fs_quota_transaction_commit, quota_default_transaction_rollback,
quota_default_try_alloc, quota_default_try_alloc_bytes, quota_default_test_alloc_bytes, quota_default_alloc, quota_default_free } };
#endif -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.1 (Darwin) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFEm4vQE2gsBSKjZHQRAhedAKCs+fugNvqM7/k1pNA9UWCzvMhjWwCg58qD B1+9+tTV/rFGaBu4XE4vi8M= =JzdC -----END PGP SIGNATURE----- -- Internet Connection High Quality Web Hosting http://www.internetconnection.net/