quota-fs.c revision 5670571cacaeb192fdc26ca2efd79734381796c0
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen/* Copyright (C) 2005-2006 Timo Sirainen */
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen/* Only for reporting filesystem quota */
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "lib.h"
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#include "array.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "str.h"
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen#include "mountpoint.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "quota-private.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include "quota-fs.h"
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#ifdef HAVE_FS_QUOTA
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include <stdio.h>
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include <stdlib.h>
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen#include <fcntl.h>
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include <unistd.h>
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#include <sys/stat.h>
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen#ifdef HAVE_LINUX_DQBLK_XFS_H
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen# include <linux/dqblk_xfs.h>
5e4c116a411967f1a012ac4f79732a724b5f6cc1Timo Sirainen# define HAVE_XFS_QUOTA
5e4c116a411967f1a012ac4f79732a724b5f6cc1Timo Sirainen#elif defined (HAVE_XFS_XQM_H)
5e4c116a411967f1a012ac4f79732a724b5f6cc1Timo Sirainen# include <xfs/xqm.h> /* CentOS 4.x at least uses this */
5e4c116a411967f1a012ac4f79732a724b5f6cc1Timo Sirainen# define HAVE_XFS_QUOTA
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen#endif
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#ifdef HAVE_RQUOTA
fdbcd3027578d35cb6e12b44c06a46905024e300Timo Sirainen# include "rquota_xdr.c"
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen# define RQUOTA_GETQUOTA_TIMEOUT_SECS 10
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#endif
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen#ifndef DEV_BSIZE
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen# define DEV_BSIZE 512
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen#endif
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen#ifdef HAVE_STRUCT_DQBLK_CURSPACE
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen# define dqb_curblocks dqb_curspace
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen#endif
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen
4c74f086031dc6ce5c65cc0f949753a03a00c686Timo Sirainen/* Older sys/quota.h doesn't define _LINUX_QUOTA_VERSION at all, which means
4c74f086031dc6ce5c65cc0f949753a03a00c686Timo Sirainen it supports only v1 quota */
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen#ifndef _LINUX_QUOTA_VERSION
4c74f086031dc6ce5c65cc0f949753a03a00c686Timo Sirainen# define _LINUX_QUOTA_VERSION 1
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen#endif
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct fs_quota_mountpoint {
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen int refcount;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen char *mount_path;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen char *device_path;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen char *type;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_SOLARIS
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen int fd;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen char *path;
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen#endif
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen};
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct fs_quota_root {
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen struct quota_root root;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen char *storage_mount_path;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen uid_t uid;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen gid_t gid;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct fs_quota_mountpoint *mount;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen unsigned int inode_per_mail:1;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen unsigned int user_disabled:1;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen unsigned int group_disabled:1;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen};
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenextern struct quota_backend quota_backend_fs;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct quota_root *fs_quota_alloc(void)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct fs_quota_root *root;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen root = i_new(struct fs_quota_root, 1);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen root->uid = geteuid();
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen root->gid = getegid();
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return &root->root;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainenstatic int fs_quota_init(struct quota_root *_root, const char *args)
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen{
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen const char *const *tmp;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen if (args == NULL)
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen return 0;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen for (tmp = t_strsplit(args, ":"); *tmp != NULL; tmp++) {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen if (strcmp(*tmp, "user") == 0)
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen root->group_disabled = TRUE;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen else if (strcmp(*tmp, "group") == 0)
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen root->user_disabled = TRUE;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen else if (strncmp(*tmp, "mount=", 6) == 0) {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen i_free(root->storage_mount_path);
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen root->storage_mount_path = i_strdup(*tmp + 6);
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen } else {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen i_error("fs quota: Invalid parameter: %s", *tmp);
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen return -1;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen }
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen }
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen return 0;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen}
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic void fs_quota_mountpoint_free(struct fs_quota_mountpoint *mount)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen if (--mount->refcount > 0)
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen return;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_SOLARIS
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (mount->fd != -1) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (close(mount->fd) < 0)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_error("close(%s) failed: %m", mount->path);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(mount->path);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen#endif
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(mount->device_path);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(mount->mount_path);
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen i_free(mount->type);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(mount);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic void fs_quota_deinit(struct quota_root *_root)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (root->mount != NULL)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen fs_quota_mountpoint_free(root->mount);
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen i_free(root->storage_mount_path);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_free(root);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen}
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstatic struct fs_quota_mountpoint *fs_quota_mountpoint_get(const char *dir)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct fs_quota_mountpoint *mount;
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen struct mountpoint point;
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen int ret;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen ret = mountpoint_get(dir, default_pool, &point);
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen if (ret <= 0)
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return NULL;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen mount = i_new(struct fs_quota_mountpoint, 1);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen mount->refcount = 1;
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen mount->device_path = point.device_path;
11ead0d848f1751c8274e3422fa48fc7d9aee2e9Timo Sirainen mount->mount_path = point.mount_path;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen mount->type = point.type;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen return mount;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen#define QUOTA_ROOT_MATCH(root, mount) \
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen ((root)->root.backend.name == quota_backend_fs.name && \
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen ((root)->storage_mount_path == NULL || \
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen strcmp((root)->storage_mount_path, (mount)->mount_path) == 0))
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic struct fs_quota_root *
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenfs_quota_root_find_mountpoint(struct quota *quota,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen const struct fs_quota_mountpoint *mount)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen{
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_root *const *roots;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct fs_quota_root *empty = NULL;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen unsigned int i, count;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen roots = array_get(&quota->roots, &count);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen for (i = 0; i < count; i++) {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)roots[i];
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen if (QUOTA_ROOT_MATCH(root, mount)) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (root->mount == NULL)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen empty = root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen else if (strcmp(root->mount->mount_path,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen mount->mount_path) == 0)
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return root;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return empty;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen}
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic void fs_quota_storage_added(struct quota *quota,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct mail_storage *storage)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen struct fs_quota_mountpoint *mount;
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct fs_quota_root *root;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen struct quota_root *const *roots;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen const char *dir;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen unsigned int i, count;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen bool is_file, inode_per_mail;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen dir = mail_storage_get_mailbox_path(storage, "", &is_file);
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen mount = fs_quota_mountpoint_get(dir);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen if (getenv("DEBUG") != NULL) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_info("fs quota add storage dir = %s", dir);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_info("fs quota block device = %s", mount->device_path);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen i_info("fs quota mount point = %s", mount->mount_path);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root = fs_quota_root_find_mountpoint(quota, mount);
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen if (root == NULL || (root != NULL && root->mount != NULL)) {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen /* already exists */
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen fs_quota_mountpoint_free(mount);
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen return;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen#ifdef FS_QUOTA_SOLARIS
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen if (mount->path == NULL) {
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen mount->path = i_strconcat(mount->mount_path, "/quotas", NULL);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen mount->fd = open(mount->path, O_RDONLY);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen if (mount->fd == -1 && errno != ENOENT)
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen i_error("open(%s) failed: %m", mount->path);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen }
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen#endif
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen /* FIXME: pretty ugly to hardcode these */
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen inode_per_mail =
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen strcmp(storage->name, "maildir") == 0 ||
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen strcmp(storage->name, "cydir") == 0;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->mount = mount;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen root->inode_per_mail = inode_per_mail;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen /* if there are more unused quota roots, copy this mount to them */
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen roots = array_get(&quota->roots, &count);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen for (i = 0; i < count; i++) {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)roots[i];
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen if (QUOTA_ROOT_MATCH(root, mount) && root->mount == NULL) {
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen mount->refcount++;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen root->mount = mount;
5670571cacaeb192fdc26ca2efd79734381796c0Timo Sirainen root->inode_per_mail = inode_per_mail;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen }
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainenstatic const char *const *
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainenfs_quota_root_get_resources(struct quota_root *_root)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen static const char *resources_kb[] = {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen NULL
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen };
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen static const char *resources_kb_messages[] = {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen QUOTA_NAME_STORAGE_KILOBYTES,
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen QUOTA_NAME_MESSAGES,
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen NULL
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen };
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen return root->inode_per_mail ? resources_kb_messages : resources_kb;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#ifdef HAVE_RQUOTA
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen/* retrieve user quota from a remote host */
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainenstatic int do_rquota(struct fs_quota_root *root, bool bytes,
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen uint64_t *value_r, uint64_t *limit_r)
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen{
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen struct getquota_rslt result;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen struct getquota_args args;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen struct timeval timeout;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen enum clnt_stat call_status;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen CLIENT *cl;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen struct fs_quota_mountpoint *mount = root->mount;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen const char *host;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen char *path;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen path = strchr(mount->device_path, ':');
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (path == NULL) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_error("quota-fs: %s is not a valid NFS device path",
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen mount->device_path);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen host = t_strdup_until(mount->device_path, path);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen path++;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (getenv("DEBUG") != NULL) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_info("quota-fs: host=%s, path=%s, uid=%s",
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen host, path, dec2str(root->uid));
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen /* clnt_create() polls for a while to establish a connection */
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen cl = clnt_create(host, RQUOTAPROG, RQUOTAVERS, "udp");
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (cl == NULL) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_error("quota-fs: could not contact RPC service on %s",
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen host);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
21aa3c764494fc308e8fdb1a9b4f9df3f260e4f8Timo Sirainen /* Establish some RPC credentials */
21aa3c764494fc308e8fdb1a9b4f9df3f260e4f8Timo Sirainen auth_destroy(cl->cl_auth);
21aa3c764494fc308e8fdb1a9b4f9df3f260e4f8Timo Sirainen cl->cl_auth = authunix_create_default();
21aa3c764494fc308e8fdb1a9b4f9df3f260e4f8Timo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen /* make the rquota call on the remote host */
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen args.gqa_pathp = path;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen args.gqa_uid = root->uid;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen timeout.tv_usec = 0;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA,
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen (xdrproc_t)xdr_getquota_args, (char *)&args,
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen (xdrproc_t)xdr_getquota_rslt, (char *)&result,
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen timeout);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen /* the result has been deserialized, let the client go */
21aa3c764494fc308e8fdb1a9b4f9df3f260e4f8Timo Sirainen auth_destroy(cl->cl_auth);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen clnt_destroy(cl);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (call_status != RPC_SUCCESS) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen const char *rpc_error_msg = clnt_sperrno(call_status);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_error("quota-fs: remote rquota call failed: %s",
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen rpc_error_msg);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen switch (result.status) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen case Q_OK: {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen /* convert the results from blocks to bytes */
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen rquota *rq = &result.getquota_rslt_u.gqr_rquota;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (rq->rq_active) {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen if (bytes) {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = (uint64_t)rq->rq_curblocks *
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen (uint64_t)rq->rq_bsize;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = (uint64_t)rq->rq_bsoftlimit *
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen (uint64_t)rq->rq_bsize;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen } else {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = rq->rq_curfiles;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = rq->rq_fsoftlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (getenv("DEBUG") != NULL) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_info("quota-fs: uid=%s, value=%llu, "
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen "limit=%llu, active=%d", dec2str(root->uid),
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen (unsigned long long)*value_r,
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen (unsigned long long)*limit_r, rq->rq_active);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return 1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen case Q_NOQUOTA:
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen if (getenv("DEBUG") != NULL) {
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_info("quota-fs: uid=%s, limit=unlimited",
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen dec2str(root->uid));
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return 1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen case Q_EPERM:
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_error("quota-fs: permission denied to rquota service");
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen default:
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen i_error("quota-fs: unrecognized status code (%d) "
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen "from rquota service", result.status);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen}
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#endif
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#if defined(FS_QUOTA_LINUX) || defined(FS_QUOTA_BSDAIX)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenstatic void fs_quota_root_disable(struct fs_quota_root *root, bool group)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen{
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (group)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen root->group_disabled = TRUE;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen else
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen root->user_disabled = TRUE;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen}
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#endif
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_LINUX
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainenstatic int
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenfs_quota_get_linux(struct fs_quota_root *root, bool group, bool bytes,
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen uint64_t *value_r, uint64_t *limit_r)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen struct dqblk dqblk;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen int type, id;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen type = group ? GRPQUOTA : USRQUOTA;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen id = group ? root->gid : root->uid;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
5e4c116a411967f1a012ac4f79732a724b5f6cc1Timo Sirainen#ifdef HAVE_XFS_QUOTA
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen if (strcmp(root->mount->type, "xfs") == 0) {
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen struct fs_disk_quota xdqblk;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (quotactl(QCMD(Q_XGETQUOTA, type),
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen root->mount->device_path,
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen id, (caddr_t)&xdqblk) < 0) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (errno == ESRCH) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen fs_quota_root_disable(root, group);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen i_error("%d quotactl(Q_XGETQUOTA, %s) failed: %m",
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen errno, root->mount->device_path);
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen return -1;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen if (bytes) {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen /* values always returned in 512 byte blocks */
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = xdqblk.d_bcount * 512;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = xdqblk.d_blk_softlimit * 512;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen } else {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = xdqblk.d_icount;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = xdqblk.d_ino_softlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen } else
92654af7b19ff1bfc0df427e5ffcb19750fbf79aTimo Sirainen#endif
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen {
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen /* ext2, ext3 */
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (quotactl(QCMD(Q_GETQUOTA, type),
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen root->mount->device_path,
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen id, (caddr_t)&dqblk) < 0) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (errno == ESRCH) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen fs_quota_root_disable(root, group);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen root->mount->device_path);
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen if (errno == EINVAL) {
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen i_error("Dovecot was compiled with Linux quota "
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen "v%d support, try changing it "
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen "(--with-linux-quota configure option)",
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen _LINUX_QUOTA_VERSION);
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen return -1;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen if (bytes) {
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#if _LINUX_QUOTA_VERSION == 1
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_curblocks * 1024;
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#else
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_curblocks;
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#endif
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = dqblk.dqb_bsoftlimit * 1024;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen } else {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_curinodes;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_isoftlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return 1;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_BSDAIX
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenstatic int
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenfs_quota_get_bsdaix(struct fs_quota_root *root, bool group, bool bytes,
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen uint64_t *value_r, uint64_t *limit_r)
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen{
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen struct dqblk dqblk;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen int type, id;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen type = group ? GRPQUOTA : USRQUOTA;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen id = group ? root->gid : root->uid;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (quotactl(root->mount->mount_path, QCMD(Q_GETQUOTA, type),
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen id, (void *)&dqblk) < 0) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (errno == ESRCH) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen fs_quota_root_disable(root, group);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
87c7e8404e2534e90cf212043e3c2d9245884003Timo Sirainen root->mount->mount_path);
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return -1;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen }
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen if (bytes) {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen } else {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_curinodes;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_isoftlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return 1;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_SOLARIS
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenstatic int
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenfs_quota_get_solaris(struct fs_quota_root *root, bool bytes,
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen uint64_t *value_r, uint64_t *limit_r)
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen{
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen struct dqblk dqblk;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen struct quotctl ctl;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (root->mount->fd == -1)
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen return 0;
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen ctl.op = Q_GETQUOTA;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen ctl.uid = root->uid;
94a54cd65ff887eefefb213a2df5577dc658f186Timo Sirainen ctl.addr = (caddr_t)&dqblk;
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen if (ioctl(root->mount->fd, Q_QUOTACTL, &ctl) < 0) {
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen i_error("ioctl(%s, Q_QUOTACTL) failed: %m", root->mount->path);
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen return -1;
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen }
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen if (bytes) {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen } else {
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_curfiles;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen *value_r = dqblk.dqb_fsoftlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return 1;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenstatic int
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenfs_quota_get_one_resource(struct fs_quota_root *root, bool group, bool bytes,
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen uint64_t *value_r, uint64_t *limit_r)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen{
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (group) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (root->group_disabled)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen } else {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (root->user_disabled)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#ifdef FS_QUOTA_LINUX
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return fs_quota_get_linux(root, group, bytes, value_r, limit_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#elif defined (FS_QUOTA_BSDAIX)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return fs_quota_get_bsdaix(root, group, bytes, value_r, limit_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#else
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (group) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen /* not supported */
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return fs_quota_get_solaris(root, bytes, value_r, limit_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#endif
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen}
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenstatic int
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenfs_quota_get_resource(struct quota_root *_root, const char *name,
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen uint64_t *value_r, uint64_t *limit_r)
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen{
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen bool bytes;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen int ret;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen *value_r = 0;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen *limit_r = 0;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen if (root->mount == NULL ||
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) != 0 &&
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen strcasecmp(name, QUOTA_NAME_MESSAGES) != 0))
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return 0;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen bytes = strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef HAVE_RQUOTA
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen if (strcmp(root->mount->type, "nfs") == 0) {
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen int ret;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen t_push();
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen ret = do_rquota(root, bytes, value_r, limit_r);
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen t_pop();
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return ret;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen ret = fs_quota_get_one_resource(root, FALSE, bytes,
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen value_r, limit_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (ret != 0)
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return ret;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen /* fallback to group quota */
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return fs_quota_get_one_resource(root, TRUE, bytes, value_r, limit_r);
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenstatic int
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainenfs_quota_update(struct quota_root *root __attr_unused__,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen struct quota_transaction_context *ctx __attr_unused__)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return 0;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct quota_backend quota_backend_fs = {
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen "fs",
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen {
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fs_quota_alloc,
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen fs_quota_init,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen fs_quota_deinit,
12dc81583d1958cb301a617e19fbd40e8d376397Timo Sirainen NULL,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fs_quota_storage_added,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen fs_quota_root_get_resources,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen fs_quota_get_resource,
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen fs_quota_update
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen};
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#endif