quota-fs.c revision 548a518357ff77755e458410a217e872c6cf3455
/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
/* Only for reporting filesystem quota */
#include "lib.h"
#include "array.h"
#include "str.h"
#include "hostpid.h"
#include "mountpoint.h"
#include "quota-private.h"
#include "quota-fs.h"
#ifdef HAVE_FS_QUOTA
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef HAVE_LINUX_DQBLK_XFS_H
# include <linux/dqblk_xfs.h>
# define HAVE_XFS_QUOTA
#elif defined (HAVE_XFS_XQM_H)
# define HAVE_XFS_QUOTA
#endif
#ifdef HAVE_RQUOTA
# include "rquota.h"
# define RQUOTA_GETQUOTA_TIMEOUT_SECS 10
#endif
#ifndef DEV_BSIZE
# ifdef DQBSIZE
# else
# define DEV_BSIZE 512
# endif
#endif
#ifdef HAVE_STRUCT_DQBLK_CURSPACE
# define dqb_curblocks dqb_curspace
#endif
it supports only v1 quota */
#ifndef _LINUX_QUOTA_VERSION
# define _LINUX_QUOTA_VERSION 1
#endif
struct fs_quota_mountpoint {
int refcount;
char *mount_path;
char *device_path;
char *type;
unsigned int block_size;
#ifdef FS_QUOTA_SOLARIS
int fd;
char *path;
#endif
};
struct fs_quota_root {
struct quota_root root;
char *storage_mount_path;
struct fs_quota_mountpoint *mount;
unsigned int inode_per_mail:1;
unsigned int user_disabled:1;
unsigned int group_disabled:1;
};
extern struct quota_backend quota_backend_fs;
static struct quota_root *fs_quota_alloc(void)
{
struct fs_quota_root *root;
}
static const char *
{
/* when filesystem quota is used, temp files will decrease the user's
quota if they're written under user's home. for example with lda
large mails are also first written to this temp directory, so if it
were in user's home, the user would always have two have twice
as much space available as necessary. */
}
{
const char *const *tmp;
return 0;
} else {
return -1;
}
}
return 0;
}
{
return;
#ifdef FS_QUOTA_SOLARIS
}
#endif
}
{
}
{
struct fs_quota_mountpoint *mount;
struct mountpoint point;
int ret;
if (ret <= 0)
return NULL;
#ifdef FS_QUOTA_SOLARIS
#endif
i_error("quota-fs: %s is not a valid NFS device path",
mount->device_path);
return NULL;
}
}
return mount;
}
static struct fs_quota_root *
const struct fs_quota_mountpoint *mount)
{
struct quota_root *const *roots;
unsigned int i, count;
for (i = 0; i < count; i++) {
mount->mount_path) == 0)
return root;
}
}
return empty;
}
struct fs_quota_mountpoint *mount)
{
struct quota_root *const *roots;
unsigned int i, count;
#ifdef FS_QUOTA_SOLARIS
#ifdef HAVE_RQUOTA
/* using rquota for this mount */
} else
#endif
}
#endif
/* if there are more unused quota roots, copy this mount to them */
for (i = 0; i < count; i++) {
}
}
}
{
struct fs_quota_mountpoint *mount;
struct quota_root *const *roots;
unsigned int i, count;
for (i = 0; i < count; i++) {
continue;
}
}
struct mail_namespace *ns)
{
struct fs_quota_mountpoint *mount;
struct fs_quota_root *root;
const char *dir;
}
else
}
/* we would actually want to do this only once after all quota roots
are created, but there's no way to do this right now */
}
static const char *const *
{
static const char *resources_kb[] = {
};
static const char *resources_kb_messages[] = {
};
}
#ifdef HAVE_RQUOTA
{
struct getquota_rslt result;
struct getquota_args args;
enum clnt_stat call_status;
const char *host;
char *path;
path++;
i_debug("quota-fs: host=%s, path=%s, uid=%s, %s",
}
/* clnt_create() polls for a while to establish a connection */
i_error("quota-fs: could not contact RPC service on %s",
host);
return -1;
}
/* Establish some RPC credentials */
/* make the rquota call on the remote host */
timeout);
/* the result has been deserialized, let the client go */
if (call_status != RPC_SUCCESS) {
i_error("quota-fs: remote rquota call failed: %s",
return -1;
}
case Q_OK: {
/* convert the results from blocks to bytes */
if (bytes) {
} else {
}
i_debug("quota-fs: uid=%s, value=%llu, limit=%llu",
(unsigned long long)*value_r,
(unsigned long long)*limit_r);
}
return 1;
}
case Q_NOQUOTA:
i_debug("quota-fs: uid=%s, limit=unlimited",
}
return 1;
case Q_EPERM:
i_error("quota-fs: permission denied to rquota service");
return -1;
default:
i_error("quota-fs: unrecognized status code (%d) "
return -1;
}
}
static int
{
#if defined(EXT_RQUOTAVERS) && defined(GRPQUOTA)
struct getquota_rslt result;
enum clnt_stat call_status;
const char *host;
char *path;
path++;
i_debug("quota-fs: host=%s, path=%s, gid=%s, %s",
}
/* clnt_create() polls for a while to establish a connection */
i_error("quota-fs: could not contact RPC service on %s (group)",
host);
return -1;
}
/* Establish some RPC credentials */
/* make the rquota call on the remote host */
timeout);
/* the result has been deserialized, let the client go */
if (call_status != RPC_SUCCESS) {
i_error("quota-fs: remote ext rquota call failed: %s",
return -1;
}
case Q_OK: {
/* convert the results from blocks to bytes */
if (bytes) {
} else {
}
i_debug("quota-fs: gid=%s, value=%llu, limit=%llu",
(unsigned long long)*value_r,
(unsigned long long)*limit_r);
}
return 1;
}
case Q_NOQUOTA:
i_debug("quota-fs: gid=%s, limit=unlimited",
}
return 1;
case Q_EPERM:
i_error("quota-fs: permission denied to ext rquota service");
return -1;
default:
i_error("quota-fs: unrecognized status code (%d) "
return -1;
}
#else
i_error("quota-fs: rquota not compiled with group support");
return -1;
#endif
}
#endif
#if defined(FS_QUOTA_LINUX) || defined(FS_QUOTA_BSDAIX)
{
if (group)
else
}
#endif
#ifdef FS_QUOTA_LINUX
static int
{
#ifdef HAVE_XFS_QUOTA
struct fs_disk_quota xdqblk;
return 0;
}
i_error("%d quotactl(Q_XGETQUOTA, %s) failed: %m",
return -1;
}
if (bytes) {
/* values always returned in 512 byte blocks */
} else {
}
} else
#endif
{
/* ext2, ext3 */
return 0;
}
i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
i_error("Dovecot was compiled with Linux quota "
"v%d support, try changing it "
"(CPPFLAGS=-D_LINUX_QUOTA_VERSION=%d configure)",
}
return -1;
}
if (bytes) {
#if _LINUX_QUOTA_VERSION == 1
#else
#endif
} else {
}
}
return 1;
}
#endif
#ifdef FS_QUOTA_BSDAIX
static int
{
return 0;
}
i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
return -1;
}
if (bytes) {
} else {
}
return 1;
}
#endif
#ifdef FS_QUOTA_HPUX
static int
{
return 0;
}
i_error("quotactl(Q_GETQUOTA, %s) failed: %m",
return -1;
}
if (bytes) {
} else {
}
return 1;
}
#endif
#ifdef FS_QUOTA_SOLARIS
static int
{
return 0;
return -1;
}
if (bytes) {
} else {
}
return 1;
}
#endif
static int
{
if (group) {
if (root->group_disabled)
return 0;
} else {
if (root->user_disabled)
return 0;
}
#ifdef FS_QUOTA_LINUX
#elif defined (FS_QUOTA_BSDAIX)
#else
if (group) {
/* not supported */
return 0;
}
#ifdef FS_QUOTA_HPUX
#else
#endif
#endif
}
{
const char *mailbox_path;
bool match;
return TRUE;
return FALSE;
}
i_debug("stat(%s) failed: %m",
}
return FALSE;
}
}
return match;
}
static int
{
bool bytes;
int ret;
*value_r = 0;
return 0;
#ifdef HAVE_RQUOTA
T_BEGIN {
} T_END;
} else
#endif
{
if (ret == 0) {
/* fallback to group quota */
}
}
if (ret <= 0)
return ret;
/* update limit */
if (bytes)
else
return 1;
}
static int
{
return 0;
}
struct quota_backend quota_backend_fs = {
"fs",
{
NULL,
NULL,
}
};
#endif