bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
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"
abc8539e7ab1f4c1e853a1369d128e0194ea1692Timo Sirainen#include "hostpid.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>
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
23ad3970cd22adb6c875caf95fa791548849f0d1Timo Sirainen# include "rquota.h"
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen# define RQUOTA_GETQUOTA_TIMEOUT_SECS 10
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#endif
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen#ifndef DEV_BSIZE
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen# ifdef DQBSIZE
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen# define DEV_BSIZE DQBSIZE /* AIX */
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen# else
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen# define DEV_BSIZE 512
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen# endif
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen#endif
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen#ifdef HAVE_STRUCT_DQBLK_CURSPACE
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen# define dqb_curblocks dqb_curspace
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen#endif
e101ed4afa1cfe5bb478491cbb5b8e7ff3de36ceTimo Sirainen
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen/* Very old sys/quota.h doesn't define _LINUX_QUOTA_VERSION at all, which means
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen it supports only v1 quota. However, new sys/quota.h (glibc 2.25) removes
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen support for v1 entirely and again it doesn't define it. I guess we can just
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen assume v2 now, and if someone still wants v1 support they can add
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen -D_LINUX_QUOTA_VERSION=1 to CFLAGS. */
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen#ifndef _LINUX_QUOTA_VERSION
39eefc53d06cf9790c6e3180a67b68e89eb71313Timo Sirainen# define _LINUX_QUOTA_VERSION 2
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen#endif
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen#define mount_type_is_nfs(mount) \
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen (strcmp((mount)->type, "nfs") == 0 || \
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen strcmp((mount)->type, "nfs4") == 0)
f9b62248553c15ed6e3297a23390f79bdc03d416Timo 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;
efd364275cb375df44fd7cd9b9aea3df2dd467bfTimo Sirainen unsigned int block_size;
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
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool inode_per_mail:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool user_disabled:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool group_disabled:1;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen#ifdef FS_QUOTA_NETBSD
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen struct quotahandle *qh;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen#endif
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
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitovstatic void handle_user_param(struct quota_root *_root, const char *param_value ATTR_UNUSED)
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov{
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov ((struct fs_quota_root *)_root)->group_disabled = TRUE;
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov}
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitovstatic void handle_group_param(struct quota_root *_root, const char *param_value ATTR_UNUSED)
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov{
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov ((struct fs_quota_root *)_root)->user_disabled = TRUE;
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov}
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitovstatic void handle_inode_param(struct quota_root *_root, const char *param_value ATTR_UNUSED)
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov{
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov ((struct fs_quota_root *)_root)->inode_per_mail = TRUE;
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov}
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitovstatic void handle_mount_param(struct quota_root *_root, const char *param_value)
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov{
d32f4c43ddfe51fd757c15fe1821287ab5b3caf5Martti Rannanjärvi struct fs_quota_root *root = (struct fs_quota_root *)_root;
d32f4c43ddfe51fd757c15fe1821287ab5b3caf5Martti Rannanjärvi i_free(root->storage_mount_path);
d32f4c43ddfe51fd757c15fe1821287ab5b3caf5Martti Rannanjärvi root->storage_mount_path = i_strdup(param_value);
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov}
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainenstatic int fs_quota_init(struct quota_root *_root, const char *args,
9b61a6db87c026656f8d2ae214e4486b98a069c0Timo Sirainen const char **error_r)
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen{
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov const struct quota_param_parser fs_params[] = {
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov {.param_name = "user", .param_handler = handle_user_param},
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov {.param_name = "group", .param_handler = handle_group_param},
d32f4c43ddfe51fd757c15fe1821287ab5b3caf5Martti Rannanjärvi {.param_name = "mount=", .param_handler = handle_mount_param},
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov {.param_name = "inode_per_mail", .param_handler = handle_inode_param},
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov quota_param_hidden, quota_param_noenforcing, quota_param_ns,
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov {.param_name = NULL}
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov };
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov
fde14422caabc3c4ac4a6c5e3e5cf176cedd90a6Timo Sirainen if (quota_parse_parameters(_root, &args, error_r, fs_params, TRUE) < 0)
efbb018262400ca272ae1d173b2db6f068516d71Sergey Kitov return -1;
e2e64c109827f782e9e20b50a15c7489479bcadaTimo Sirainen _root->auto_updating = TRUE;
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
a943ed0f901e312445fd393249b91932797bba79Josef 'Jeff' Sipek i_close_fd_path(&mount->fd, mount->path);
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;
efd364275cb375df44fd7cd9b9aea3df2dd467bfTimo Sirainen mount->block_size = point.block_size;
bae914d7dac4fffc4e3147438ea26d98cc1de7a1Timo Sirainen#ifdef FS_QUOTA_SOLARIS
bae914d7dac4fffc4e3147438ea26d98cc1de7a1Timo Sirainen mount->fd = -1;
bae914d7dac4fffc4e3147438ea26d98cc1de7a1Timo Sirainen#endif
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen if (mount_type_is_nfs(mount)) {
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (strchr(mount->device_path, ':') == NULL) {
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen i_error("quota-fs: %s is not a valid NFS device path",
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen mount->device_path);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen fs_quota_mountpoint_free(mount);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return NULL;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
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
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainenstatic void
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainenfs_quota_mount_init(struct fs_quota_root *root,
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen struct fs_quota_mountpoint *mount, const char *dir)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen struct quota_root *const *roots;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen unsigned int i, count;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen#ifdef FS_QUOTA_SOLARIS
10ae1846ac55dda424467e7230f0f77e3434fa5cTimo Sirainen#ifdef HAVE_RQUOTA
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen if (mount_type_is_nfs(mount)) {
10ae1846ac55dda424467e7230f0f77e3434fa5cTimo Sirainen /* using rquota for this mount */
10ae1846ac55dda424467e7230f0f77e3434fa5cTimo Sirainen } else
10ae1846ac55dda424467e7230f0f77e3434fa5cTimo Sirainen#endif
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
3ccfcf0856958cb9208a9fc51c3bdf13c58ad52aTimo Sirainen root->mount = mount;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen if (root->root.quota->set->debug) {
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen i_debug("fs quota add mailbox dir = %s", dir);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen i_debug("fs quota block device = %s", mount->device_path);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen i_debug("fs quota mount point = %s", mount->mount_path);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen i_debug("fs quota mount type = %s", mount->type);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen }
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen /* if there are more unused quota roots, copy this mount to them */
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen roots = array_get(&root->root.quota->roots, &count);
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen for (i = 0; i < count; i++) {
b8d232d88018c5cafd2f3be5a181d318137a45f2Timo Sirainen 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;
3aaf560f83bd578d951b5026b5b0ffb58f86dccbTimo Sirainen }
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainenstatic void fs_quota_add_missing_mounts(struct quota *quota)
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen{
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen struct fs_quota_mountpoint *mount;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen struct quota_root *const *roots;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen unsigned int i, count;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen roots = array_get(&quota->roots, &count);
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen for (i = 0; i < count; i++) {
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)roots[i];
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen if (root->root.backend.name != quota_backend_fs.name ||
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen root->storage_mount_path == NULL || root->mount != NULL)
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen continue;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen mount = fs_quota_mountpoint_get(root->storage_mount_path);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen if (mount != NULL) {
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen fs_quota_mount_init(root, mount,
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen root->storage_mount_path);
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen }
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen }
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen}
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstatic void fs_quota_namespace_added(struct quota *quota,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen struct mail_namespace *ns)
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen{
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen struct fs_quota_mountpoint *mount;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen struct fs_quota_root *root;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen const char *dir;
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (!mailbox_list_get_root_path(ns->list, MAILBOX_LIST_PATH_TYPE_MAILBOX,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &dir))
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mount = NULL;
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen else
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen mount = fs_quota_mountpoint_get(dir);
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen if (mount != NULL) {
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen root = fs_quota_root_find_mountpoint(quota, mount);
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen if (root != NULL && root->mount == NULL)
079a251730d3ede9b1243fe3c2a15c1ff2c57094Timo Sirainen fs_quota_mount_init(root, mount, dir);
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen else
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen fs_quota_mountpoint_free(mount);
b19feb85569a6ad96e60d8246723561331213b8aTimo Sirainen }
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen /* we would actually want to do this only once after all quota roots
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen are created, but there's no way to do this right now */
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen fs_quota_add_missing_mounts(quota);
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo Sirainen}
ceb88add1fc9f7f25e1ce75f7dae947bb63ae0a0Timo 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
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen#if defined(FS_QUOTA_LINUX) || defined(FS_QUOTA_BSDAIX) || \
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen defined(FS_QUOTA_NETBSD) || defined(HAVE_RQUOTA)
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainenstatic void fs_quota_root_disable(struct fs_quota_root *root, bool group)
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen{
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen if (group)
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen root->group_disabled = TRUE;
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen else
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen root->user_disabled = TRUE;
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen}
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen#endif
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#ifdef HAVE_RQUOTA
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainenstatic void
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenrquota_get_result(const rquota *rq,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *count_value_r, uint64_t *count_limit_r)
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen{
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen /* use soft limits if they exist, fallback to hard limits */
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen /* convert the results from blocks to bytes */
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = (uint64_t)rq->rq_curblocks *
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen (uint64_t)rq->rq_bsize;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (rq->rq_bsoftlimit != 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)rq->rq_bsoftlimit *
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen (uint64_t)rq->rq_bsize;
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen } else {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)rq->rq_bhardlimit *
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen (uint64_t)rq->rq_bsize;
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = rq->rq_curfiles;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (rq->rq_fsoftlimit != 0)
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = rq->rq_fsoftlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen else
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = rq->rq_fhardlimit;
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen}
f5f9099ac93110513bb18f366d1536d174dcfad8Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainendo_rquota_user(struct fs_quota_root *root,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_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, ':');
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen i_assert(path != NULL);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen host = t_strdup_until(mount->device_path, path);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen path++;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen /* For NFSv4, we send the filesystem path without initial /. Server
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen prepends proper NFS pseudoroot automatically and uses this for
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen detection of NFSv4 mounts. */
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen if (strcmp(root->mount->type, "nfs4") == 0) {
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen while (*path == '/')
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen path++;
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen }
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen
c7ec3797312157be2b01925c95aff9599d04ef42Timo Sirainen if (root->root.quota->set->debug) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen i_debug("quota-fs: host=%s, path=%s, uid=%s",
47c4991dc627010c92674cb3af6bc9d5089720e7Timo 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) {
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "could not contact RPC service on %s", 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);
73cdeeae4ccae9930973dfb6a5b4835c79bdba49Sergey Kitov
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
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "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: {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen rquota_get_result(&result.getquota_rslt_u.gqr_rquota,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen bytes_value_r, bytes_limit_r,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen count_value_r, count_limit_r);
c7ec3797312157be2b01925c95aff9599d04ef42Timo Sirainen if (root->root.quota->set->debug) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi i_debug("quota-fs: uid=%s, bytes=%"PRIu64"/%"PRIu64" "
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "files=%"PRIu64"/%"PRIu64,
548a518357ff77755e458410a217e872c6cf3455Timo Sirainen dec2str(root->uid),
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi *bytes_value_r, *bytes_limit_r,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi *count_value_r, *count_limit_r);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return 1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen case Q_NOQUOTA:
c7ec3797312157be2b01925c95aff9599d04ef42Timo Sirainen if (root->root.quota->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("quota-fs: uid=%s, limit=unlimited",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk dec2str(root->uid));
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen fs_quota_root_disable(root, FALSE);
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen return 0;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen case Q_EPERM:
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi *error_r = "permission denied to rquota service";
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen default:
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "unrecognized status code (%d) from rquota service",
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi result.status);
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen return -1;
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen }
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen}
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4e9665287d5e321fd2574a1f2c1a99a94a0d3f79Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainendo_rquota_group(struct fs_quota_root *root ATTR_UNUSED,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r ATTR_UNUSED,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_limit_r ATTR_UNUSED,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *count_value_r ATTR_UNUSED,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_limit_r ATTR_UNUSED,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_r)
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen{
6dddf1d27c0f72756c790735d1dedde6591cc15dTimo Sirainen#if defined(EXT_RQUOTAVERS) && defined(GRPQUOTA)
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen struct getquota_rslt result;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen ext_getquota_args args;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen struct timeval timeout;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen enum clnt_stat call_status;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen CLIENT *cl;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen struct fs_quota_mountpoint *mount = root->mount;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen const char *host;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen char *path;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen path = strchr(mount->device_path, ':');
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen i_assert(path != NULL);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen host = t_strdup_until(mount->device_path, path);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen path++;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (root->root.quota->set->debug) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen i_debug("quota-fs: host=%s, path=%s, gid=%s",
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen host, path, dec2str(root->gid));
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen /* clnt_create() polls for a while to establish a connection */
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen cl = clnt_create(host, RQUOTAPROG, EXT_RQUOTAVERS, "udp");
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (cl == NULL) {
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "could not contact RPC service on %s (group)", host);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return -1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen /* Establish some RPC credentials */
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen auth_destroy(cl->cl_auth);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen cl->cl_auth = authunix_create_default();
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen /* make the rquota call on the remote host */
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen args.gqa_pathp = path;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen args.gqa_id = root->gid;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen args.gqa_type = GRPQUOTA;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen timeout.tv_sec = RQUOTA_GETQUOTA_TIMEOUT_SECS;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen timeout.tv_usec = 0;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen call_status = clnt_call(cl, RQUOTAPROC_GETQUOTA,
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen (xdrproc_t)xdr_ext_getquota_args, (char *)&args,
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen (xdrproc_t)xdr_getquota_rslt, (char *)&result,
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen timeout);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen /* the result has been deserialized, let the client go */
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen auth_destroy(cl->cl_auth);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen clnt_destroy(cl);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (call_status != RPC_SUCCESS) {
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen const char *rpc_error_msg = clnt_sperrno(call_status);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "remote ext rquota call failed: %s", rpc_error_msg);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return -1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen switch (result.status) {
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen case Q_OK: {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen rquota_get_result(&result.getquota_rslt_u.gqr_rquota,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen bytes_value_r, bytes_limit_r,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen count_value_r, count_limit_r);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (root->root.quota->set->debug) {
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi i_debug("quota-fs: gid=%s, bytes=%"PRIu64"/%"PRIu64" "
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi "files=%"PRIu64"/%"PRIu64,
548a518357ff77755e458410a217e872c6cf3455Timo Sirainen dec2str(root->gid),
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi *bytes_value_r, *bytes_limit_r,
47a5a7e8296f3b8f2fac9a0659d4de3f2723ba4aMartti Rannanjärvi *count_value_r, *count_limit_r);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return 1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen case Q_NOQUOTA:
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen if (root->root.quota->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("quota-fs: gid=%s, limit=unlimited",
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk dec2str(root->gid));
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen fs_quota_root_disable(root, TRUE);
738bdc36e50f5acb829e8fbeed9b77afee0c6de0Timo Sirainen return 0;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen case Q_EPERM:
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi *error_r = "permission denied to ext rquota service";
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return -1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen default:
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "unrecognized status code (%d) from ext rquota service",
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi result.status);
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return -1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen }
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen#else
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi *error_r = "rquota not compiled with group support";
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen return -1;
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen#endif
4c7caf83adc56d54e2ecec0a803f5ca9b6d0498dTimo Sirainen}
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen#endif
9e96947aa6185341cbdd1140cb216fab3270ccbaTimo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_LINUX
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_linux(struct fs_quota_root *root, bool group,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_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 }
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "errno=%d, quotactl(Q_XGETQUOTA, %s) failed: %m",
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen errno, root->mount->device_path);
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen return -1;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen /* values always returned in 512 byte blocks */
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_value_r = xdqblk.d_bcount * 512ULL;
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_limit_r = xdqblk.d_blk_softlimit * 512ULL;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*bytes_limit_r == 0) {
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_limit_r = xdqblk.d_blk_hardlimit * 512ULL;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = xdqblk.d_icount;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = xdqblk.d_ino_softlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*count_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = xdqblk.d_ino_hardlimit;
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 }
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "quotactl(Q_GETQUOTA, %s) failed: %m",
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen root->mount->device_path);
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen if (errno == EINVAL) {
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf("%s, "
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi "Dovecot was compiled with Linux quota "
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen "v%d support, try changing it "
64e33505784bb6f6ab83ce062d82870868751eb5Timo Sirainen "(CPPFLAGS=-D_LINUX_QUOTA_VERSION=%d configure)",
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r,
64e33505784bb6f6ab83ce062d82870868751eb5Timo Sirainen _LINUX_QUOTA_VERSION,
64e33505784bb6f6ab83ce062d82870868751eb5Timo Sirainen _LINUX_QUOTA_VERSION == 1 ? 2 : 1);
2e0e52f27469bf4eba8d7e88f1716f0a19824ba5Timo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen return -1;
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
979e2379225b05df63ca3a0c55064edbc03d7afbTimo Sirainen
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#if _LINUX_QUOTA_VERSION == 1
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_value_r = dqblk.dqb_curblocks * 1024ULL;
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#else
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = dqblk.dqb_curblocks;
e59857800e22c3e1c90578763dbf7d61a5fc79f2Timo Sirainen#endif
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_limit_r = dqblk.dqb_bsoftlimit * 1024ULL;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*bytes_limit_r == 0) {
15c365ef8fadf433160deb3f59442616ed0569dcTimo Sirainen *bytes_limit_r = dqblk.dqb_bhardlimit * 1024ULL;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = dqblk.dqb_curinodes;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_isoftlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*count_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_ihardlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
a2871d937a75288bcd7177b2680d4e5096a7f3cbTimo Sirainen }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return 1;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_BSDAIX
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_bsdaix(struct fs_quota_root *root, bool group,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_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 }
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "quotactl(Q_GETQUOTA, %s) failed: %m",
87c7e8404e2534e90cf212043e3c2d9245884003Timo Sirainen root->mount->mount_path);
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return -1;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*bytes_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bhardlimit * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = dqblk.dqb_curinodes;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_isoftlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*count_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_ihardlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen return 1;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen#ifdef FS_QUOTA_NETBSD
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_netbsd(struct fs_quota_root *root, bool group,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_r)
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen{
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen struct quotakey qk;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen struct quotaval qv;
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen struct quotahandle *qh;
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen int ret;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen if ((qh = quota_open(root->mount->mount_path)) == NULL) {
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi *error_r = t_strdup_printf("cannot open quota for %s: %m",
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi root->mount->mount_path);
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen fs_quota_root_disable(root, group);
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen return 0;
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen }
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen qk.qk_idtype = group ? QUOTA_IDTYPE_GROUP : QUOTA_IDTYPE_USER;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen qk.qk_id = group ? root->gid : root->uid;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen
4adefdb40c7ffcac3d8f8279cdf52d9f72d39636Teemu Huovila for (int i = 0; i < 2; i++) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen qk.qk_objtype = i == 0 ? QUOTA_OBJTYPE_BLOCKS : QUOTA_OBJTYPE_FILES;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (quota_get(qh, &qk, &qv) != 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (errno == ESRCH) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen fs_quota_root_disable(root, group);
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen return 0;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "quotactl(Q_GETQUOTA, %s) failed: %m",
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen root->mount->mount_path);
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen ret = -1;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen break;
73cdeeae4ccae9930973dfb6a5b4835c79bdba49Sergey Kitov }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (i == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = qv.qv_usage * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = qv.qv_softlimit * DEV_BSIZE;
bcecb676b4f8ee1c8e16c47a711fee86859d84bfTimo Sirainen } else {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = qv.qv_usage;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = qv.qv_softlimit;
bcecb676b4f8ee1c8e16c47a711fee86859d84bfTimo Sirainen }
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen ret = 1;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen }
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen quota_close(qh);
5f83be0c55c71e15b62cbc275f8dd4b3e80e18b6Timo Sirainen return ret;
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen}
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen#endif
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen#ifdef FS_QUOTA_HPUX
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_hpux(struct fs_quota_root *root,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_r)
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen{
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen struct dqblk dqblk;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen if (quotactl(Q_GETQUOTA, root->mount->device_path,
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen root->uid, &dqblk) < 0) {
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen if (errno == ESRCH) {
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen root->user_disabled = TRUE;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen return 0;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen }
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "quotactl(Q_GETQUOTA, %s) failed: %m",
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen root->mount->device_path);
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen return -1;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen }
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = (uint64_t)dqblk.dqb_curblocks *
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen root->mount->block_size;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bsoftlimit *
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen root->mount->block_size;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*bytes_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bhardlimit *
efd364275cb375df44fd7cd9b9aea3df2dd467bfTimo Sirainen root->mount->block_size;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = dqblk.dqb_curfiles;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_fsoftlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*count_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_fhardlimit;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen }
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen return 1;
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen}
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen#endif
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef FS_QUOTA_SOLARIS
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_solaris(struct fs_quota_root *root,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_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) {
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi *error_r = t_strdup_printf(
12d7f667b636405ae54dcc4cb3031f4ba52aff04Martti Rannanjärvi "ioctl(%s, Q_QUOTACTL) failed: %m",
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi root->mount->path);
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen return -1;
ac756824dc2be28eda7e9f70f1a694469f88d8bfTimo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_value_r = (uint64_t)dqblk.dqb_curblocks * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bsoftlimit * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*bytes_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *bytes_limit_r = (uint64_t)dqblk.dqb_bhardlimit * DEV_BSIZE;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_value_r = dqblk.dqb_curfiles;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_fsoftlimit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (*count_limit_r == 0) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *count_limit_r = dqblk.dqb_fhardlimit;
e4cbaae481f5e980dca4df1a819d8df127456e4dTimo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return 1;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainenstatic int
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainenfs_quota_get_resources(struct fs_quota_root *root, bool group,
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t *bytes_value_r, uint64_t *bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi uint64_t *count_value_r, uint64_t *count_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi const char **error_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
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi return fs_quota_get_linux(root, group, bytes_value_r, bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi count_value_r, count_limit_r, error_r);
26ada766cfff6ebfb91d100936118cf8aa51e3aeTimo Sirainen#elif defined (FS_QUOTA_NETBSD)
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi return fs_quota_get_netbsd(root, group, bytes_value_r, bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi count_value_r, count_limit_r, error_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#elif defined (FS_QUOTA_BSDAIX)
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi return fs_quota_get_bsdaix(root, group, bytes_value_r, bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi count_value_r, count_limit_r, error_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#else
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen if (group) {
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen /* not supported */
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen return 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen }
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen#ifdef FS_QUOTA_HPUX
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi return fs_quota_get_hpux(root, bytes_value_r, bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi count_value_r, count_limit_r, error_r);
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen#else
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi return fs_quota_get_solaris(root, bytes_value_r, bytes_limit_r,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi count_value_r, count_limit_r, error_r);
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen#endif
45031ba153608eb33af22ee0d242c3e5e426486dTimo Sirainen#endif
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen}
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainenstatic bool fs_quota_match_box(struct quota_root *_root, struct mailbox *box)
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen{
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen struct stat mst, rst;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen const char *mailbox_path;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen bool match;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
f468a767041b7bb567c3dde04e9d885e98177eaeTimo Sirainen if (root->storage_mount_path == NULL)
f468a767041b7bb567c3dde04e9d885e98177eaeTimo Sirainen return TRUE;
f468a767041b7bb567c3dde04e9d885e98177eaeTimo Sirainen
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen if (mailbox_get_path_to(box, MAILBOX_LIST_PATH_TYPE_MAILBOX,
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen &mailbox_path) <= 0)
9fc97c8aa8190df87624d214bcc5d0b5362bec93Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (stat(mailbox_path, &mst) < 0) {
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (errno != ENOENT)
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen i_error("stat(%s) failed: %m", mailbox_path);
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen if (stat(root->storage_mount_path, &rst) < 0) {
c7ec3797312157be2b01925c95aff9599d04ef42Timo Sirainen if (_root->quota->set->debug) {
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk i_debug("stat(%s) failed: %m",
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen root->storage_mount_path);
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen return FALSE;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen match = CMP_DEV_T(mst.st_dev, rst.st_dev);
c7ec3797312157be2b01925c95aff9599d04ef42Timo Sirainen if (_root->quota->set->debug) {
73cdeeae4ccae9930973dfb6a5b4835c79bdba49Sergey Kitov i_debug("box=%s mount=%s match=%s", mailbox_path,
e5acc283bf030b0b5c79ca4e52d315c516a299faPascal Volk root->storage_mount_path, match ? "yes" : "no");
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen }
73cdeeae4ccae9930973dfb6a5b4835c79bdba49Sergey Kitov return match;
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen}
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvistatic enum quota_get_result
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainenfs_quota_get_resource(struct quota_root *_root, const char *name,
a525be16a69367f43765d20c873b5f168c5b7ea3Martti Rannanjärvi uint64_t *value_r, const char **error_r)
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen{
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen struct fs_quota_root *root = (struct fs_quota_root *)_root;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t bytes_value, count_value;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen uint64_t bytes_limit = 0, count_limit = 0;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen int ret;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen *value_r = 0;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi if (root->mount == NULL) {
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi if (root->storage_mount_path != NULL)
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = t_strdup_printf(
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi "Mount point unknown for path %s",
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi root->storage_mount_path);
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi else
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = "Mount point unknown";
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_INTERNAL_ERROR;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi }
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) != 0 &&
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi strcasecmp(name, QUOTA_NAME_MESSAGES) != 0) {
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi *error_r = QUOTA_UNKNOWN_RESOURCE_ERROR_STRING;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_UNKNOWN_RESOURCE;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi }
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#ifdef HAVE_RQUOTA
f9b62248553c15ed6e3297a23390f79bdc03d416Timo Sirainen if (mount_type_is_nfs(root->mount)) {
d77b5c30f4e757add1028de85e7ad95fccd96f98Martti Rannanjärvi ret = root->user_disabled ? 0 :
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi do_rquota_user(root, &bytes_value, &bytes_limit,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &count_value, &count_limit, error_r);
d77b5c30f4e757add1028de85e7ad95fccd96f98Martti Rannanjärvi if (ret == 0 && !root->group_disabled)
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi ret = do_rquota_group(root, &bytes_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &bytes_limit, &count_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &count_limit, error_r);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen } else
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen#endif
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen {
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi ret = fs_quota_get_resources(root, FALSE, &bytes_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &bytes_limit, &count_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &count_limit, error_r);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen if (ret == 0) {
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen /* fallback to group quota */
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi ret = fs_quota_get_resources(root, TRUE, &bytes_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &bytes_limit, &count_value,
9a603e8651212925bc15ba89abdbe9ea92a0d903Martti Rannanjärvi &count_limit, error_r);
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen }
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi if (ret < 0)
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_INTERNAL_ERROR;
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi else if (ret == 0)
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
4bbac9612c0b16bd4c7f03326a7a2cdc163014d8Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (strcasecmp(name, QUOTA_NAME_STORAGE_BYTES) == 0)
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *value_r = bytes_value;
3851ad9fcb25635f02b46d44586742ef1081876bTimo Sirainen else
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen *value_r = count_value;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen if (_root->bytes_limit != (int64_t)bytes_limit ||
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen _root->count_limit != (int64_t)count_limit) {
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen /* update limit */
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen _root->bytes_limit = bytes_limit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen _root->count_limit = count_limit;
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen /* limits have changed, so we'll need to recalculate
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen relative quota rules */
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen quota_root_recalculate_relative_rules(_root->set, bytes_limit, count_limit);
47c4991dc627010c92674cb3af6bc9d5089720e7Timo Sirainen }
1379bb74c2855aaf3415fdfe965164a44ac3c001Martti Rannanjärvi return QUOTA_GET_RESULT_LIMITED;
29fe652c01b24298ee9e5825a103279106f0e263Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
73cdeeae4ccae9930973dfb6a5b4835c79bdba49Sergey Kitovstatic int
43d32cbe60fdaef2699d99f1ca259053e9350411Timo Sirainenfs_quota_update(struct quota_root *root ATTR_UNUSED,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi struct quota_transaction_context *ctx ATTR_UNUSED,
7b3b617e946d5b32078baa821f5fc05f775e1dfeMartti Rannanjärvi const char **error_r ATTR_UNUSED)
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen{
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen return 0;
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen}
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainenstruct quota_backend quota_backend_fs = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .name = "fs",
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .v = {
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .alloc = fs_quota_alloc,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .init = fs_quota_init,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .deinit = fs_quota_deinit,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .namespace_added = fs_quota_namespace_added,
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resources = fs_quota_root_get_resources,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .get_resource = fs_quota_get_resource,
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .update = fs_quota_update,
6d6bbe8787354bbb69d0c03187adfe0f497d70b8Timo Sirainen
5997118fa7aee2535edac28092261ca085a958aeMartti Rannanjärvi .match_box = fs_quota_match_box,
82995cc154a929f37aa486a72a6485e9f8d34a30Timo Sirainen }
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen};
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen
a35cbba04d0a2823da98e693bd09a051addffdb2Timo Sirainen#endif