Mercurial > dovecot > original-hg > dovecot-1.2
changeset 3751:768770a01733 HEAD
quotactl() quota checking support
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Wed, 14 Dec 2005 23:34:01 +0200 |
parents | b752272e6355 |
children | aea926f980b8 |
files | configure.in src/plugins/quota/Makefile.am src/plugins/quota/quota-fs.c src/plugins/quota/quota-fs.h src/plugins/quota/quota.c |
diffstat | 5 files changed, 353 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.in Wed Dec 14 23:28:44 2005 +0200 +++ b/configure.in Wed Dec 14 23:34:01 2005 +0200 @@ -15,7 +15,8 @@ AM_ICONV AC_CHECK_HEADERS(strings.h stdint.h unistd.h dirent.h \ - sys/uio.h sys/sysmacros.h sys/resource.h sys/select.h libgen.h) + sys/uio.h sys/sysmacros.h sys/resource.h sys/select.h libgen.h \ + sys/quota.h sys/fs/ufs_quota.h ufs/ufs/quota.h mntent.h sys/mnttab.h) # check posix headers AC_CHECK_HEADERS(sys/time.h) @@ -311,7 +312,7 @@ AC_CHECK_FUNCS(fcntl flock lockf inet_aton sigaction getpagesize madvise \ strcasecmp stricmp vsnprintf vsyslog writev pread \ setrlimit setproctitle seteuid setreuid setegid setresgid \ - strtoull strtouq setpriority) + strtoull strtouq setpriority quotactl getmntent) dnl * I/O loop function have_ioloop=no
--- a/src/plugins/quota/Makefile.am Wed Dec 14 23:28:44 2005 +0200 +++ b/src/plugins/quota/Makefile.am Wed Dec 14 23:34:01 2005 +0200 @@ -11,6 +11,7 @@ libquota_plugin_la_SOURCES = \ quota.c \ + quota-fs.c \ quota-dict.c \ quota-dirsize.c \ quota-plugin.c \ @@ -18,6 +19,7 @@ noinst_HEADERS = \ quota.h \ + quota-fs.h \ quota-plugin.h \ quota-private.h
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/quota/quota-fs.c Wed Dec 14 23:34:01 2005 +0200 @@ -0,0 +1,309 @@ +/* Copyright (C) 2005 Timo Sirainen */ + +/* Only for reporting filesystem quota */ + +#include "lib.h" +#include "str.h" +#include "quota-private.h" +#include "quota-fs.h" + +#ifdef HAVE_FS_QUOTA + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/stat.h> + +#define MTAB_PATH "/etc/mtab" + +struct fs_quota { + struct quota quota; + + pool_t pool; + const char *device; + const char *error; + + unsigned int blk_size; + uid_t uid; + + struct quota_root root; +}; + +struct fs_quota_root_iter { + struct quota_root_iter iter; + + int sent; +}; + +extern struct quota fs_quota; + +static const char *path_to_device(const char *path, unsigned int *blk_size_r) +{ +#ifdef HAVE_STATFS_MNTFROMNAME + struct statfs buf; + + if (statfs(path, &buf) < 0) { + i_error("statfs(%s) failed: %m", path); + return NULL; + } + + *blk_size_r = buf.f_bsize; + return t_strdup(buf.f_mntfromname); +#else + struct mntent *ent; + struct stat st, st2; + const char *dev = NULL; + FILE *f; + + if (stat(path, &st) < 0) { + i_error("stat(%s) failed: %m", path); + return NULL; + } + *blk_size_r = st.st_blksize; + + f = fopen(MTAB_PATH, "r"); + if (f == NULL) { + i_error("open(%s) failed: %m", MTAB_PATH); + return NULL; + } + while ((ent = getmntent(f)) != NULL) { + if (strcmp(ent->mnt_type, MNTTYPE_SWAP) == 0 || + strcmp(ent->mnt_type, MNTTYPE_IGNORE) == 0) + continue; + + if (stat(ent->mnt_fsname, &st2) == 0 && + CMP_DEV_T(st.st_dev, st2.st_dev)) { + dev = t_strdup(ent->mnt_fsname); + break; + } + } + endmntent(f); + return dev; +#endif +} + +static struct quota *fs_quota_init(const char *data) +{ + struct fs_quota *quota; + const char *device; + pool_t pool; + unsigned int blk_size = 0; + + device = path_to_device(data, &blk_size); + + if (getenv("DEBUG") != NULL) { + i_info("fs quota path = %s", data); + i_info("fs quota block device = %s", + device == NULL ? "(unknown)" : device); + } + + if (device == NULL) + return NULL; + + pool = pool_alloconly_create("quota", 1024); + quota = p_new(pool, struct fs_quota, 1); + quota->pool = pool; + quota->quota = fs_quota; + quota->device = p_strdup(pool, device); + quota->uid = geteuid(); + quota->blk_size = blk_size; + + quota->root.quota = "a->quota; + return "a->quota; +} + +static void fs_quota_deinit(struct quota *_quota) +{ + struct fs_quota *quota = (struct fs_quota *)_quota; + + pool_unref(quota->pool); +} + +static struct quota_root_iter * +fs_quota_root_iter_init(struct quota *quota, + struct mailbox *box __attr_unused__) +{ + struct fs_quota_root_iter *iter; + + iter = i_new(struct fs_quota_root_iter, 1); + iter->iter.quota = quota; + return &iter->iter; +} + +static struct quota_root * +fs_quota_root_iter_next(struct quota_root_iter *_iter) +{ + struct fs_quota_root_iter *iter = + (struct fs_quota_root_iter *)_iter; + struct fs_quota *quota = (struct fs_quota *)_iter->quota; + + if (iter->sent) + return NULL; + + iter->sent = TRUE; + return "a->root; +} + +static int fs_quota_root_iter_deinit(struct quota_root_iter *iter) +{ + i_free(iter); + return 0; +} + +static struct quota_root * +fs_quota_root_lookup(struct quota *_quota, const char *name) +{ + struct fs_quota *quota = (struct fs_quota *)_quota; + + if (*name == '\0') + return "a->root; + else + return NULL; +} + +static const char * +fs_quota_root_get_name(struct quota_root *root __attr_unused__) +{ + return ""; +} + +static const char *const * +fs_quota_root_get_resources(struct quota_root *root __attr_unused__) +{ + static const char *resources[] = { QUOTA_NAME_STORAGE, NULL }; + + return resources; +} + +static int +fs_quota_root_create(struct quota *_quota, + const char *name __attr_unused__, + struct quota_root **root_r __attr_unused__) +{ + struct fs_quota *quota = (struct fs_quota *)_quota; + + quota->error = "Permission denied"; + return -1; +} + +static int +fs_quota_get_resource(struct quota_root *root, const char *name, + uint64_t *value_r, uint64_t *limit_r) +{ + struct fs_quota *quota = (struct fs_quota *)root->quota; + struct dqblk dqblk; + + *value_r = 0; + *limit_r = 0; + + if (strcasecmp(name, QUOTA_NAME_STORAGE) != 0) + return 0; + + if (quotactl(QCMD(Q_GETQUOTA, USRQUOTA), quota->device, + quota->uid, (void *)&dqblk) < 0) { + i_error("quotactl(Q_GETQUOTA, %s) failed: %m", quota->device); + quota->error = "Internal quota error"; + return -1; + } + *value_r = dqblk.dqb_curblocks * quota->blk_size / 1024; + *limit_r = dqblk.dqb_bsoftlimit * quota->blk_size / 1024; + return 1; +} + +static int +fs_quota_set_resource(struct quota_root *root, + const char *name __attr_unused__, + uint64_t value __attr_unused__) +{ + struct fs_quota *quota = (struct fs_quota *)root->quota; + + quota->error = "Permission denied"; + return -1; +} + +static struct quota_transaction_context * +fs_quota_transaction_begin(struct quota *quota) +{ + struct quota_transaction_context *ctx; + + ctx = i_new(struct quota_transaction_context, 1); + ctx->quota = quota; + return ctx; +} + +static int +fs_quota_transaction_commit(struct quota_transaction_context *ctx) +{ + i_free(ctx); + return 0; +} + +static void +fs_quota_transaction_rollback(struct quota_transaction_context *ctx) +{ + i_free(ctx); +} + +static int +fs_quota_try_alloc(struct quota_transaction_context *ctx __attr_unused__, + struct mail *mail __attr_unused__, + int *too_large_r __attr_unused__) +{ + /* no-op */ + return 1; +} + +static void +fs_quota_alloc(struct quota_transaction_context *ctx __attr_unused__, + struct mail *mail __attr_unused__) +{ + /* no-op */ +} + +static void +fs_quota_free(struct quota_transaction_context *ctx __attr_unused__, + struct mail *mail __attr_unused__) +{ + /* no-op */ +} + +static const char *fs_quota_last_error(struct quota *_quota) +{ + struct fs_quota *quota = (struct fs_quota *)_quota; + + return quota->error; +} + +struct quota fs_quota = { + "fs", + + fs_quota_init, + fs_quota_deinit, + + fs_quota_root_iter_init, + fs_quota_root_iter_next, + fs_quota_root_iter_deinit, + + fs_quota_root_lookup, + + fs_quota_root_get_name, + fs_quota_root_get_resources, + + fs_quota_root_create, + fs_quota_get_resource, + fs_quota_set_resource, + + fs_quota_transaction_begin, + fs_quota_transaction_commit, + fs_quota_transaction_rollback, + + fs_quota_try_alloc, + fs_quota_alloc, + fs_quota_free, + + fs_quota_last_error, + + ARRAY_INIT +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/plugins/quota/quota-fs.h Wed Dec 14 23:34:01 2005 +0200 @@ -0,0 +1,27 @@ +#ifndef __QUOTA_FS_H +#define __QUOTA_FS_H + +#define HAVE_FS_QUOTA + +#ifdef HAVE_SYS_QUOTA_H +# include <sys/quota.h> /* Linux */ +#elif defined(HAVE_SYS_FS_UFS_QUOTA_H) +# include <sys/fs/ufs_quota.h> /* Solaris */ +#elif defined(HAVE_UFS_UFS_QUOTA_H) +# include <ufs/ufs/quota.h> /* BSDs */ +#else +# undef HAVE_FS_QUOTA +#endif + +#ifdef HAVE_STATFS_MNTFROMNAME +# include <sys/param.h> /* BSDs */ +# include <sys/mount.h> +#elif defined(HAVE_MNTENT_H) +# include <mntent.h> /* Linux */ +#elif defined(HAVE_SYS_MNTTAB_H) +# include <sys/mnttab.h> /* Solaris */ +#else +# undef HAVE_FS_QUOTA +#endif + +#endif
--- a/src/plugins/quota/quota.c Wed Dec 14 23:28:44 2005 +0200 +++ b/src/plugins/quota/quota.c Wed Dec 14 23:34:01 2005 +0200 @@ -3,13 +3,21 @@ #include "lib.h" #include "array.h" #include "quota-private.h" +#include "quota-fs.h" unsigned int quota_module_id = 0; extern struct quota dirsize_quota; extern struct quota dict_quota; +extern struct quota fs_quota; -static struct quota *quota_classes[] = { &dirsize_quota, &dict_quota }; +static struct quota *quota_classes[] = { + &dirsize_quota, + &dict_quota, +#ifdef HAVE_FS_QUOTA + &fs_quota +#endif +}; #define QUOTA_CLASS_COUNT (sizeof(quota_classes)/sizeof(quota_classes[0])) struct quota *quota_init(const char *data) @@ -44,10 +52,11 @@ void quota_deinit(struct quota *quota) { - array_t *module_contexts = "a->quota_module_contexts; + /* make a copy, since quota is freed */ + array_t module_contexts = quota->quota_module_contexts; quota->deinit(quota); - array_free(module_contexts); + array_free(&module_contexts); } struct quota_root_iter *