summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2011-11-17 00:02:59 +0100
committerJan Kara <jack@suse.cz>2011-11-17 00:02:59 +0100
commit40e09a3b49827699d770f8144f973d4928f248b2 (patch)
tree6a23009f53705cdce7b714ea0c3c9148e5ab9be6
parentb21068b188539573f39525c296202c071ad594fe (diff)
downloadlinuxquota-40e09a3b49827699d770f8144f973d4928f248b2.tar.gz
Add support for quotas on ext4 in system files
Teach quota tools to handle quotas in system files on ext4. For this to work, we slightly rework mount option parsing to allow distinguisting between ext4 with classical quota files and ext4 with quotas in system files. Signed-off-by: Jan Kara <jack@suse.cz>
-rw-r--r--convertquota.c18
-rw-r--r--quot.c22
-rw-r--r--quot.h2
-rw-r--r--quota.h2
-rw-r--r--quotacheck.c130
-rw-r--r--quotaio.c50
-rw-r--r--quotaio.h7
-rw-r--r--quotaon.c67
-rw-r--r--quotaon.h4
-rw-r--r--quotaon_xfs.c25
-rw-r--r--quotasys.c307
-rw-r--r--quotasys.h30
-rw-r--r--rquota_server.c4
13 files changed, 349 insertions, 319 deletions
diff --git a/convertquota.c b/convertquota.c
index 483abf1..7df948e 100644
--- a/convertquota.c
+++ b/convertquota.c
@@ -287,7 +287,7 @@ static int convert_dquot(struct dquot *dquot, char *name)
return 0;
}
-static int rename_file(int type, int fmt, struct mntent *mnt)
+static int rename_file(int type, int fmt, struct mount_entry *mnt)
{
char *qfname, namebuf[PATH_MAX];
int ret = 0;
@@ -307,19 +307,19 @@ static int rename_file(int type, int fmt, struct mntent *mnt)
return ret;
}
-static int convert_format(int type, struct mntent *mnt)
+static int convert_format(int type, struct mount_entry *mnt)
{
struct quota_handle *qo;
int ret = 0;
if (!(qo = init_io(mnt, type, infmt, IOI_INITSCAN))) {
errstr(_("Cannot open old format file for %ss on %s\n"),
- type2name(type), mnt->mnt_dir);
+ type2name(type), mnt->me_dir);
return -1;
}
if (!(qn = new_io(mnt, type, outfmt))) {
errstr(_("Cannot create file for %ss for new format on %s: %s\n"),
- type2name(type), mnt->mnt_dir, strerror(errno));
+ type2name(type), mnt->me_dir, strerror(errno));
end_io(qo);
return -1;
}
@@ -332,7 +332,7 @@ static int convert_format(int type, struct mntent *mnt)
return ret;
}
-static int convert_endian(int type, struct mntent *mnt)
+static int convert_endian(int type, struct mount_entry *mnt)
{
int ret = 0;
int ofd;
@@ -341,7 +341,7 @@ static int convert_endian(int type, struct mntent *mnt)
if (get_qf_name(mnt, type, QF_VFSV0, NF_EXIST, &qfname) < 0)
return -1;
if ((ofd = open(qfname, O_RDONLY)) < 0) {
- errstr(_("Cannot open old quota file on %s: %s\n"), mnt->mnt_dir, strerror(errno));
+ errstr(_("Cannot open old quota file on %s: %s\n"), mnt->me_dir, strerror(errno));
free(qfname);
return -1;
}
@@ -352,7 +352,7 @@ static int convert_endian(int type, struct mntent *mnt)
}
if (!(qn = new_io(mnt, type, QF_VFSV0))) {
errstr(_("Cannot create file for %ss for new format on %s: %s\n"),
- type2name(type), mnt->mnt_dir, strerror(errno));
+ type2name(type), mnt->me_dir, strerror(errno));
close(ofd);
return -1;
}
@@ -369,7 +369,7 @@ static int convert_endian(int type, struct mntent *mnt)
return rename_file(type, QF_VFSV0, mnt);
}
-static int convert_file(int type, struct mntent *mnt)
+static int convert_file(int type, struct mount_entry *mnt)
{
switch (action) {
case ACT_FORMAT:
@@ -383,7 +383,7 @@ static int convert_file(int type, struct mntent *mnt)
int main(int argc, char **argv)
{
- struct mntent *mnt;
+ struct mount_entry *mnt;
int ret = 0;
gettexton();
diff --git a/quot.c b/quot.c
index d9114a4..efff122 100644
--- a/quot.c
+++ b/quot.c
@@ -73,8 +73,8 @@ char *progname;
static void mounttable(void);
static char *idname(__uint32_t, int);
-static void report(const char *, char *, int);
-static void creport(const char *, char *);
+static void report(const char *, const char *, int);
+static void creport(const char *, const char *);
static void usage(void)
{
@@ -139,20 +139,20 @@ int main(int argc, char **argv)
static void mounttable(void)
{
int doit = 0;
- struct mntent *mntp;
+ struct mount_entry *mntp;
while ((mntp = get_next_mount())) {
/* Currently, only XFS is implemented... */
- if (strcmp(mntp->mnt_type, MNTTYPE_XFS) == 0) {
- checkXFS(mntp->mnt_fsname, mntp->mnt_dir);
+ if (strcmp(mntp->me_type, MNTTYPE_XFS) == 0) {
+ checkXFS(mntp->me_devname, mntp->me_dir);
doit = 1;
}
/* ...additional filesystems types here. */
if (doit) {
- if (cflag) creport(mntp->mnt_fsname, mntp->mnt_dir);
- if (!cflag && uflag) report(mntp->mnt_fsname, mntp->mnt_dir, 0);
- if (!cflag && gflag) report(mntp->mnt_fsname, mntp->mnt_dir, 1);
+ if (cflag) creport(mntp->me_devname, mntp->me_dir);
+ if (!cflag && uflag) report(mntp->me_devname, mntp->me_dir, 0);
+ if (!cflag && gflag) report(mntp->me_devname, mntp->me_dir, 1);
}
}
}
@@ -170,7 +170,7 @@ static int qcmp(du_t * p1, du_t * p2)
return 0;
}
-static void creport(const char *file, char *fsdir)
+static void creport(const char *file, const char *fsdir)
{
int i;
__uint64_t t = 0;
@@ -188,7 +188,7 @@ static void creport(const char *file, char *fsdir)
(unsigned long long) (overflow + t));
}
-static void report(const char *file, char *fsdir, int type)
+static void report(const char *file, const char *fsdir, int type)
{
du_t *dp;
@@ -334,7 +334,7 @@ static void acctXFS(xfs_bstat_t *p)
}
}
-static void checkXFS(const char *file, char *fsdir)
+static void checkXFS(const char *file, const char *fsdir)
{
xfs_fsop_bulkreq_t bulkreq;
__u64 last = 0;
diff --git a/quot.h b/quot.h
index 4f3de0b..07ea39d 100644
--- a/quot.h
+++ b/quot.h
@@ -106,7 +106,7 @@ typedef struct xfs_fsop_bulkreq {
#endif
#define NBSTAT 4069 /* XFS bulkstat inodes */
-static void checkXFS(const char *file, char *fsdir);
+static void checkXFS(const char *file, const char *fsdir);
/*
* === End of XFS specific types and definitions ===
diff --git a/quota.h b/quota.h
index 565fc7e..0491975 100644
--- a/quota.h
+++ b/quota.h
@@ -95,6 +95,8 @@ struct if_dqblk {
#define IIF_FLAGS 4
#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+#define DQF_SYS_FILE 0x10000 /* Quota stored in a system file */
+
struct if_dqinfo {
u_int64_t dqi_bgrace;
u_int64_t dqi_igrace;
diff --git a/quotacheck.c b/quotacheck.c
index 129f838..2da562b 100644
--- a/quotacheck.c
+++ b/quotacheck.c
@@ -243,7 +243,7 @@ static void remove_list(void)
}
/* Get size used by file */
-static loff_t getqsize(char *fname, struct stat *st)
+static loff_t getqsize(const char *fname, struct stat *st)
{
static char ioctl_fail_warn;
int fd;
@@ -269,7 +269,7 @@ static loff_t getqsize(char *fname, struct stat *st)
/*
* Show a blitting cursor as means of visual progress indicator.
*/
-static inline void blit(char *msg)
+static inline void blit(const char *msg)
{
static int bitc = 0;
static const char bits[] = "|/-\\";
@@ -413,7 +413,7 @@ static void parse_options(int argcnt, char **argstr)
}
#if defined(EXT2_DIRECT)
-static int ext2_direct_scan(char *device)
+static int ext2_direct_scan(const char *device)
{
ext2_ino_t i_num;
ext2_filsys fs;
@@ -490,7 +490,7 @@ static int ext2_direct_scan(char *device)
* of the files to the appropriate quotas. When we find a dir we recursivly call
* ourself to scan that dir.
*/
-static int scan_dir(char *pathname)
+static int scan_dir(const char *pathname)
{
struct dirs *dir_stack = NULL;
struct dirs *new_dir;
@@ -613,18 +613,18 @@ int ask_yn(char *q, int def)
}
/* Do checks and buffer quota file into memory */
-static int process_file(struct mntent *mnt, int type)
+static int process_file(struct mount_entry *mnt, int type)
{
char *qfname = NULL;
int fd = -1, ret;
debug(FL_DEBUG, _("Going to check %s quota file of %s\n"), type2name(type),
- mnt->mnt_dir);
+ mnt->me_dir);
- if (kern_quota_on(mnt->mnt_fsname, type, cfmt) >= 0) { /* Is quota enabled? */
+ if (kern_quota_on(mnt, type, cfmt) >= 0) { /* Is quota enabled? */
if (!(flags & FL_FORCE)) {
if (flags & FL_INTERACTIVE) {
- printf(_("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n"), type2name(type), mnt->mnt_dir);
+ printf(_("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n"), type2name(type), mnt->me_dir);
if (!ask_yn(_("Should I continue"), 0)) {
printf(_("As you wish... Canceling check of this file.\n"));
return -1;
@@ -633,17 +633,17 @@ static int process_file(struct mntent *mnt, int type)
else
die(6, _("Quota for %ss is enabled on mountpoint %s so quotacheck might damage the file.\n\
Please turn quotas off or use -f to force checking.\n"),
- type2name(type), mnt->mnt_dir);
+ type2name(type), mnt->me_dir);
}
/* At least sync quotas so damage will be smaller */
if (quotactl(QCMD((kernel_iface == IFACE_GENERIC)? Q_SYNC : Q_6_5_SYNC, type),
- mnt->mnt_fsname, 0, NULL) < 0)
- die(4, _("Error while syncing quotas on %s: %s\n"), mnt->mnt_fsname, strerror(errno));
+ mnt->me_devname, 0, NULL) < 0)
+ die(4, _("Error while syncing quotas on %s: %s\n"), mnt->me_devname, strerror(errno));
}
if (!(flags & FL_NEWFILE)) { /* Need to buffer file? */
if (get_qf_name(mnt, type, cfmt, 0, &qfname) < 0) {
- errstr(_("Cannot get quotafile name for %s\n"), mnt->mnt_fsname);
+ errstr(_("Cannot get quotafile name for %s\n"), mnt->me_devname);
return -1;
}
if ((fd = open(qfname, O_RDONLY)) < 0) {
@@ -675,7 +675,7 @@ Please turn quotas off or use -f to force checking.\n"),
}
/* Backup old quotafile and rename new one to right name */
-static int rename_files(struct mntent *mnt, int type)
+static int rename_files(struct mount_entry *mnt, int type)
{
char *filename, newfilename[PATH_MAX];
struct stat st;
@@ -690,7 +690,7 @@ static int rename_files(struct mntent *mnt, int type)
debug(FL_DEBUG, _("Renaming new files to proper names.\n"));
if (get_qf_name(mnt, type, cfmt, 0, &filename) < 0)
- die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->mnt_dir);
+ die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->me_dir);
if (stat(filename, &st) < 0) { /* File doesn't exist? */
if (errno == ENOENT) {
debug(FL_DEBUG | FL_VERBOSE, _("Old file not found.\n"));
@@ -781,7 +781,7 @@ rename_new:
* quota file. As quotafiles doesn't account to quotas we don't have to
* bother about accounting new blocks for quota file
*/
-static int dump_to_file(struct mntent *mnt, int type)
+static int dump_to_file(struct mount_entry *mnt, int type)
{
struct dquot *dquot;
uint i;
@@ -828,16 +828,16 @@ static int dump_to_file(struct mntent *mnt, int type)
return -1;
}
debug(FL_DEBUG, _("Data dumped.\n"));
- if (kern_quota_on(mnt->mnt_fsname, type, cfmt) >= 0) { /* Quota turned on? */
+ if (kern_quota_on(mnt, type, cfmt) >= 0) { /* Quota turned on? */
char *filename;
if (get_qf_name(mnt, type, cfmt, NF_FORMAT, &filename) < 0)
- errstr(_("Cannot find checked quota file for %ss on %s!\n"), type2name(type), mnt->mnt_fsname);
+ errstr(_("Cannot find checked quota file for %ss on %s!\n"), type2name(type), mnt->me_devname);
else {
if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type),
- mnt->mnt_fsname, 0, NULL) < 0)
+ mnt->me_devname, 0, NULL) < 0)
errstr(_("Cannot turn %s quotas off on %s: %s\nKernel won't know about changes quotacheck did.\n"),
- type2name(type), mnt->mnt_fsname, strerror(errno));
+ type2name(type), mnt->me_devname, strerror(errno));
else {
int ret;
@@ -845,12 +845,12 @@ static int dump_to_file(struct mntent *mnt, int type)
rename_files(mnt, type);
if (kernel_iface == IFACE_GENERIC)
- ret = quotactl(QCMD(Q_QUOTAON, type), mnt->mnt_fsname, util2kernfmt(cfmt), filename);
+ ret = quotactl(QCMD(Q_QUOTAON, type), mnt->me_devname, util2kernfmt(cfmt), filename);
else
- ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->mnt_fsname, 0, filename);
+ ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->me_devname, 0, filename);
if (ret < 0)
errstr(_("Cannot turn %s quotas on on %s: %s\nKernel won't know about changes quotacheck did.\n"),
- type2name(type), mnt->mnt_fsname, strerror(errno));
+ type2name(type), mnt->me_devname, strerror(errno));
}
free(filename);
}
@@ -863,7 +863,7 @@ static int dump_to_file(struct mntent *mnt, int type)
/* Substract space used by old quota file from usage.
* Return non-zero in case of failure, zero otherwise. */
-static int sub_quota_file(struct mntent *mnt, int qtype, int ftype)
+static int sub_quota_file(struct mount_entry *mnt, int qtype, int ftype)
{
char *filename;
struct stat st;
@@ -901,16 +901,16 @@ static int sub_quota_file(struct mntent *mnt, int qtype, int ftype)
/* Buffer quotafile, run filesystem scan, dump quotafiles.
* Return non-zero value in case of failure, zero otherwise. */
-static int check_dir(struct mntent *mnt)
+static int check_dir(struct mount_entry *mnt)
{
struct stat st;
int remounted = 0;
int failed = 0;
- if (lstat(mnt->mnt_dir, &st) < 0)
- die(2, _("Cannot stat mountpoint %s: %s\n"), mnt->mnt_dir, strerror(errno));
+ if (lstat(mnt->me_dir, &st) < 0)
+ die(2, _("Cannot stat mountpoint %s: %s\n"), mnt->me_dir, strerror(errno));
if (!S_ISDIR(st.st_mode))
- die(2, _("Mountpoint %s is not a directory?!\n"), mnt->mnt_dir);
+ die(2, _("Mountpoint %s is not a directory?!\n"), mnt->me_dir);
cur_dev = st.st_dev;
files_done = dirs_done = 0;
/*
@@ -932,10 +932,10 @@ static int check_dir(struct mntent *mnt)
if (!(flags & FL_NOREMOUNT)) {
/* Now we try to remount fs read-only to prevent races when scanning filesystem */
if (mount
- (NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY,
+ (NULL, mnt->me_dir, mnt->me_type, MS_MGC_VAL | MS_REMOUNT | MS_RDONLY,
NULL) < 0 && !(flags & FL_FORCEREMOUNT)) {
if (flags & FL_INTERACTIVE) {
- printf(_("Cannot remount filesystem mounted on %s read-only. Counted values might not be right.\n"), mnt->mnt_dir);
+ printf(_("Cannot remount filesystem mounted on %s read-only. Counted values might not be right.\n"), mnt->me_dir);
if (!ask_yn(_("Should I continue"), 0)) {
printf(_("As you wish... Canceling check of this file.\n"));
failed = -1;
@@ -944,7 +944,7 @@ static int check_dir(struct mntent *mnt)
}
else {
errstr(_("Cannot remount filesystem mounted on %s read-only so counted values might not be right.\n\
-Please stop all programs writing to filesystem or use -m flag to force checking.\n"), mnt->mnt_dir);
+Please stop all programs writing to filesystem or use -m flag to force checking.\n"), mnt->me_dir);
failed = -1;
goto out;
}
@@ -954,19 +954,19 @@ Please stop all programs writing to filesystem or use -m flag to force checking.
debug(FL_DEBUG, _("Filesystem remounted read-only\n"));
}
start_scan:
- debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->mnt_fsname, mnt->mnt_dir);
+ debug(FL_VERBOSE, _("Scanning %s [%s] "), mnt->me_devname, mnt->me_dir);
#if defined(EXT2_DIRECT)
- if (!strcmp(mnt->mnt_type, MNTTYPE_EXT2) || !strcmp(mnt->mnt_type, MNTTYPE_EXT3) || !strcmp(mnt->mnt_type, MNTTYPE_NEXT3)) {
- if ((failed = ext2_direct_scan(mnt->mnt_fsname)) < 0)
+ if (!strcmp(mnt->me_type, MNTTYPE_EXT2) || !strcmp(mnt->me_type, MNTTYPE_EXT3) || !strcmp(mnt->me_type, MNTTYPE_NEXT3)) {
+ if ((failed = ext2_direct_scan(mnt->me_devname)) < 0)
goto out;
}
else {
#else
- if (mnt->mnt_dir) {
+ if (mnt->me_dir) {
#endif
if (flags & FL_VERYVERBOSE)
putchar('\n');
- if ((failed = scan_dir(mnt->mnt_dir)) < 0)
+ if ((failed = scan_dir(mnt->me_dir)) < 0)
goto out;
}
dirs_done++;
@@ -983,8 +983,8 @@ start_scan:
debug(FL_DEBUG | FL_VERBOSE, _("Checked %d directories and %d files\n"), dirs_done,
files_done);
if (remounted) {
- if (mount(NULL, mnt->mnt_dir, mnt->mnt_type, MS_MGC_VAL | MS_REMOUNT, NULL) < 0)
- die(4, _("Cannot remount filesystem %s read-write. cannot write new quota files.\n"), mnt->mnt_dir);
+ if (mount(NULL, mnt->me_dir, mnt->me_type, MS_MGC_VAL | MS_REMOUNT, NULL) < 0)
+ die(4, _("Cannot remount filesystem %s read-write. cannot write new quota files.\n"), mnt->me_dir);
debug(FL_DEBUG, _("Filesystem remounted RW.\n"));
}
if (ucheck)
@@ -997,7 +997,7 @@ out:
}
/* Detect quota format from filename of present files */
-static int detect_filename_format(struct mntent *mnt, int type)
+static int detect_filename_format(struct mount_entry *mnt, int type)
{
char *option;
struct stat statbuf;
@@ -1005,36 +1005,36 @@ static int detect_filename_format(struct mntent *mnt, int type)
int journal = 0;
int fmt;
- if (strcmp(mnt->mnt_type, MNTTYPE_XFS) == 0 ||
- strcmp(mnt->mnt_type, MNTTYPE_GFS2) == 0)
+ if (strcmp(mnt->me_type, MNTTYPE_XFS) == 0 ||
+ strcmp(mnt->me_type, MNTTYPE_GFS2) == 0)
return QF_XFS;
if (type == USRQUOTA) {
- if ((option = hasmntopt(mnt, MNTOPT_USRQUOTA)))
+ if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_USRQUOTA)))
option += strlen(MNTOPT_USRQUOTA);
- else if (hasmntopt(mnt, MNTOPT_USRJQUOTA)) {
+ else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_USRJQUOTA))) {
journal = 1;
option += strlen(MNTOPT_USRJQUOTA);
}
- else if ((option = hasmntopt(mnt, MNTOPT_QUOTA)))
+ else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_QUOTA)))
option += strlen(MNTOPT_QUOTA);
}
else {
- if ((option = hasmntopt(mnt, MNTOPT_GRPQUOTA)))
+ if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPQUOTA)))
option += strlen(MNTOPT_GRPQUOTA);
- else if (hasmntopt(mnt, MNTOPT_GRPJQUOTA)) {
+ else if ((option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPJQUOTA))) {
journal = 1;
option += strlen(MNTOPT_GRPJQUOTA);
}
}
if (!option)
- die(2, _("Cannot find quota option on filesystem %s with quotas!\n"), mnt->mnt_dir);
+ die(2, _("Cannot find quota option on filesystem %s with quotas!\n"), mnt->me_dir);
if (journal) {
char fmtbuf[64], *space;
- if (!(option = hasmntopt(mnt, MNTOPT_JQFMT))) {
+ if (!(option = str_hasmntopt(mnt->me_opts, MNTOPT_JQFMT))) {
jquota_err:
- errstr(_("Cannot detect quota format for journalled quota on %s\n"), mnt->mnt_dir);
+ errstr(_("Cannot detect quota format for journalled quota on %s\n"), mnt->me_dir);
return -1;
}
option += strlen(MNTOPT_JQFMT);
@@ -1053,7 +1053,7 @@ jquota_err:
}
else if (*option == '=') /* If the file name is specified we can't detect quota format from it... */
return -1;
- snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSV0], extensions[type]);
+ snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->me_dir, basenames[QF_VFSV0], extensions[type]);
if (!stat(namebuf, &statbuf)) {
int fd = open(namebuf, O_RDONLY);
if (fd < 0)
@@ -1065,7 +1065,7 @@ jquota_err:
}
if (errno != ENOENT)
return -1;
- snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSOLD], extensions[type]);
+ snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->me_dir, basenames[QF_VFSOLD], extensions[type]);
if (!stat(namebuf, &statbuf))
return QF_VFSOLD;
/* Old quota files don't exist, just create VFSv0 format if available */
@@ -1128,7 +1128,7 @@ warn:
/* Return 0 in case of success, non-zero otherwise. */
static int check_all(void)
{
- struct mntent *mnt;
+ struct mount_entry *mnt;
int checked = 0;
static int warned;
int failed = 0;
@@ -1136,18 +1136,18 @@ static int check_all(void)
if (init_mounts_scan((flags & FL_ALL) ? 0 : 1, &mntpoint, 0) < 0)
die(2, _("Cannot initialize mountpoint scan.\n"));
while ((mnt = get_next_mount())) {
- if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->mnt_dir, "/"))
+ if (flags & FL_ALL && flags & FL_NOROOT && !strcmp(mnt->me_dir, "/"))
continue;
- if (!compatible_fs_qfmt(mnt->mnt_type, fmt)) {
- debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->mnt_fsname, mnt->mnt_dir);
+ if (!compatible_fs_qfmt(mnt->me_type, fmt)) {
+ debug(FL_DEBUG | FL_VERBOSE, _("Skipping %s [%s]\n"), mnt->me_devname, mnt->me_dir);
continue;
}
cfmt = fmt;
- if (uwant && hasquota(mnt, USRQUOTA, 0))
+ if (uwant && me_hasquota(mnt, USRQUOTA))
ucheck = 1;
else
ucheck = 0;
- if (gwant && hasquota(mnt, GRPQUOTA, 0))
+ if (gwant && me_hasquota(mnt, GRPQUOTA))
gcheck = 1;
else
gcheck = 0;
@@ -1157,20 +1157,22 @@ static int check_all(void)
cfmt = detect_filename_format(mnt, ucheck ? USRQUOTA : GRPQUOTA);
if (cfmt == -1) {
errstr(_("Cannot guess format from filename on %s. Please specify format on commandline.\n"),
- mnt->mnt_fsname);
+ mnt->me_devname);
failed = -1;
continue;
}
debug(FL_DEBUG, _("Detected quota format %s\n"), fmt2name(cfmt));
}
- if (flags & FL_VERBOSE && !hasmntopt(mnt, MNTOPT_USRJQUOTA) &&
- !hasmntopt(mnt, MNTOPT_GRPJQUOTA) && !warned &&
- (!strcmp(mnt->mnt_type, MNTTYPE_EXT3) ||
- !strcmp(mnt->mnt_type, MNTTYPE_EXT4) ||
- !strcmp(mnt->mnt_type, MNTTYPE_NEXT3) ||
- !strcmp(mnt->mnt_type, MNTTYPE_EXT4DEV) ||
- !strcmp(mnt->mnt_type, MNTTYPE_REISER))) {
+ if (flags & FL_VERBOSE &&
+ !str_hasmntopt(mnt->me_opts, MNTOPT_USRJQUOTA) &&
+ !str_hasmntopt(mnt->me_opts, MNTOPT_GRPJQUOTA) &&
+ !warned &&
+ (!strcmp(mnt->me_type, MNTTYPE_EXT3) ||
+ !strcmp(mnt->me_type, MNTTYPE_EXT4) ||
+ !strcmp(mnt->me_type, MNTTYPE_NEXT3) ||
+ !strcmp(mnt->me_type, MNTTYPE_EXT4DEV) ||
+ !strcmp(mnt->me_type, MNTTYPE_REISER))) {
warned = 1;
warn_if_jquota_supported();
}
diff --git a/quotaio.c b/quotaio.c
index 257252d..d3c7cb6 100644
--- a/quotaio.c
+++ b/quotaio.c
@@ -37,19 +37,16 @@ struct disk_dqheader {
/*
* Detect quota format and initialize quota IO
*/
-struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
+struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int flags)
{
char *qfname = NULL;
int fd = -1, kernfmt;
struct quota_handle *h = smalloc(sizeof(struct quota_handle));
- const char *mnt_fsname = NULL;
int nameflag;
- if (!hasquota(mnt, type, 0))
+ if (!me_hasquota(mnt, type))
goto out_handle;
- if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
- goto out_handle;
- if (stat(mnt_fsname, &h->qh_stat) < 0)
+ if (stat(mnt->me_devname, &h->qh_stat) < 0)
memset(&h->qh_stat, 0, sizeof(struct stat));
h->qh_io_flags = 0;
if (flags & IOI_READONLY)
@@ -57,11 +54,10 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
if (flags & IOI_NFS_MIXED_PATHS)
h->qh_io_flags |= IOFL_NFS_MIXED_PATHS;
h->qh_type = type;
- sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
- free((char *)mnt_fsname);
- sstrncpy(h->qh_fstype, mnt->mnt_type, MAX_FSTYPE_LEN);
- sstrncpy(h->qh_dir, mnt->mnt_dir, PATH_MAX);
- if (nfs_fstype(mnt->mnt_type)) { /* NFS filesystem? */
+ sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
+ sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
+ sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
+ if (nfs_fstype(mnt->me_type)) { /* NFS filesystem? */
if (fmt != -1 && fmt != QF_RPC) { /* User wanted some other format? */
errstr(_("Only RPC quota format is allowed on NFS filesystem.\n"));
goto out_handle;
@@ -82,8 +78,8 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
goto out_handle;
}
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) || /* XFS filesystem? */
- !strcmp(mnt->mnt_type, MNTTYPE_GFS2)) { /* XFS filesystem? */
+ if (!strcmp(mnt->me_type, MNTTYPE_XFS) || /* XFS filesystem? */
+ !strcmp(mnt->me_type, MNTTYPE_GFS2)) { /* XFS filesystem? */
if (fmt != -1 && fmt != QF_XFS) { /* User wanted some other format? */
errstr(_("Only XFS quota format is allowed on XFS filesystem.\n"));
goto out_handle;
@@ -101,14 +97,14 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
}
if (kern_qfmt_supp(fmt)) { /* Quota compiled and desired format available? */
/* Quota turned on? */
- kernfmt = kern_quota_on(h->qh_quotadev, type, fmt);
+ kernfmt = kern_quota_on(mnt, type, fmt);
if (kernfmt >= 0) {
h->qh_io_flags |= IOFL_QUOTAON;
fmt = kernfmt; /* Default is kernel used format */
}
}
- if (meta_qf_fstype(mnt->mnt_type)) {
+ if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
if (!QIO_ENABLED(h)) {
errstr(_("Quota not supported by the filesystem.\n"));
goto out_handle;
@@ -193,21 +189,30 @@ out_handle:
/*
* Create new quotafile of specified format on given filesystem
*/
-struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
+struct quota_handle *new_io(struct mount_entry *mnt, int type, int fmt)
{
char *qfname;
int fd;
struct quota_handle *h;
- const char *mnt_fsname;
char namebuf[PATH_MAX];
if (fmt == -1)
fmt = QF_VFSV0;
- else if (fmt == QF_RPC || fmt == QF_XFS || meta_qf_fstype(mnt->mnt_type)) {
+ else if (fmt == QF_RPC || fmt == QF_XFS) {
errstr(_("Creation of %s quota format is not supported.\n"),
fmt2name(fmt));
return NULL;
}
+ /*
+ * For filesystems which never have quotas in quota files or for
+ * filesystems which have quotas already stored in system files we
+ * refuse to create anything.
+ */
+ if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
+ errstr(_("Quota on %s is stored in system files and must"
+ " be manipulated by fs tools.\n"), mnt->me_dir);
+ return NULL;
+ }
if (get_qf_name(mnt, type, fmt, 0, &qfname) < 0)
return NULL;
sstrncpy(namebuf, qfname, PATH_MAX);
@@ -218,16 +223,13 @@ struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
namebuf, strerror(errno));
return NULL;
}
- if (!(mnt_fsname = get_device_name(mnt->mnt_fsname)))
- goto out_fd;
h = smalloc(sizeof(struct quota_handle));
h->qh_fd = fd;
h->qh_io_flags = 0;
- sstrncpy(h->qh_quotadev, mnt_fsname, sizeof(h->qh_quotadev));
- sstrncpy(h->qh_fstype, mnt->mnt_type, MAX_FSTYPE_LEN);
- sstrncpy(h->qh_dir, mnt->mnt_dir, PATH_MAX);
- free((char *)mnt_fsname);
+ sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
+ sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
+ sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
h->qh_type = type;
h->qh_fmt = fmt;
memset(&h->qh_info, 0, sizeof(h->qh_info));
diff --git a/quotaio.h b/quotaio.h
index 3cd33ba..2c373b2 100644
--- a/quotaio.h
+++ b/quotaio.h
@@ -40,6 +40,7 @@
#define QF_RPC 3 /* RPC should be used on given filesystem */
#define QF_XFS 4 /* XFS quota format */
#define QF_META 5 /* Quota files are hidden, we don't care about the format */
+#define QF_VFSUNKNOWN 6 /* Some VFS quotas, we didn't detect particular format yet */
static inline int is_tree_qfmt(int fmt)
{
@@ -164,11 +165,13 @@ static inline void mark_quotafile_info_dirty(struct quota_handle *h)
#define QIO_ENABLED(h) ((h)->qh_io_flags & IOFL_QUOTAON)
#define QIO_RO(h) ((h)->qh_io_flags & IOFL_RO)
+struct mount_entry;
+
/* Check quota format used on specified medium and initialize it */
-struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags);
+struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int flags);
/* Create new quotafile of specified format on given filesystem */
-struct quota_handle *new_io(struct mntent *mnt, int type, int fmt);
+struct quota_handle *new_io(struct mount_entry *mnt, int type, int fmt);
/* Close quotafile */
int end_io(struct quota_handle *h);
diff --git a/quotaon.c b/quotaon.c
index f374423..a8e780f 100644
--- a/quotaon.c
+++ b/quotaon.c
@@ -197,7 +197,7 @@ static int quotarsquashonoff(const char *quotadev, int type, int flags)
/*
* Enable/disable VFS quota on given filesystem
*/
-static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, int fmt, int flags)
+static int quotaonoff(const char *quotadev, const char *quotadir, char *quotafile, int type, int fmt, int flags)
{
int qcmd, kqf;
@@ -239,42 +239,31 @@ static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type,
/*
* Enable/disable quota/rootsquash on given filesystem (version 1)
*/
-static int v1_newstate(struct mntent *mnt, int type, char *file, int flags, int fmt)
+static int v1_newstate(struct mount_entry *mnt, int type, char *file, int flags, int fmt)
{
int errs = 0;
- const char *dev = get_device_name(mnt->mnt_fsname);
- if (!dev)
- return 1;
- if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH))
- errs += quotarsquashonoff(dev, type, flags);
- errs += quotaonoff((char *)dev, mnt->mnt_dir, file, type, QF_VFSOLD, flags);
- if ((flags & STATEFLAG_ON) && hasmntopt(mnt, MNTOPT_RSQUASH))
- errs += quotarsquashonoff(dev, type, flags);
- free((char *)dev);
+ if ((flags & STATEFLAG_OFF) && str_hasmntopt(mnt->me_opts, MNTOPT_RSQUASH))
+ errs += quotarsquashonoff(mnt->me_devname, type, flags);
+ errs += quotaonoff(mnt->me_devname, mnt->me_dir, file, type, QF_VFSOLD, flags);
+ if ((flags & STATEFLAG_ON) && str_hasmntopt(mnt->me_opts, MNTOPT_RSQUASH))
+ errs += quotarsquashonoff(mnt->me_devname, type, flags);
return errs;
}
/*
* Enable/disable quota on given filesystem (generic VFS quota)
*/
-static int v2_newstate(struct mntent *mnt, int type, char *file, int flags, int fmt)
+static int v2_newstate(struct mount_entry *mnt, int type, char *file, int flags, int fmt)
{
- const char *dev = get_device_name(mnt->mnt_fsname);
- int errs = 0;
-
- if (!dev)
- return 1;
- errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, fmt, flags);
- free((char *)dev);
- return errs;
+ return quotaonoff(mnt->me_devname, mnt->me_dir, file, type, fmt, flags);
}
/*
* For both VFS quota formats, need to pass in the quota file;
* for XFS quota manager, pass on the -x command line option.
*/
-static int newstate(struct mntent *mnt, int type, char *extra)
+static int newstate(struct mount_entry *mnt, int type, char *extra)
{
int sflags, ret = 0;
@@ -282,26 +271,24 @@ static int newstate(struct mntent *mnt, int type, char *extra)
if (flags & FL_ALL)
sflags |= STATEFLAG_ALL;
- if (!strcmp(mnt->mnt_type, MNTTYPE_GFS2)) {
+ if (!strcmp(mnt->me_type, MNTTYPE_GFS2)) {
errstr(_("Cannot change state of GFS2 quota.\n"));
return 1;
- } else if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */
+ } else if (!strcmp(mnt->me_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */
if (!kern_qfmt_supp(QF_XFS)) {
errstr(_("Cannot change state of XFS quota. It's not compiled in kernel.\n"));
return 1;
}
ret = xfs_newstate(mnt, type, extra, sflags);
}
- else if (meta_qf_fstype(mnt->mnt_type)) {
- if (!hasquota(mnt, type, 0))
- return 0;
+ else if (mnt->me_qfmt[type] == QF_META) {
/* Must be non-empty because empty path is always invalid. */
ret = v2_newstate(mnt, type, ".", sflags, QF_VFSV0);
}
else {
int usefmt;
- if (!hasquota(mnt, type, 0))
+ if (!me_hasquota(mnt, type))
return 0;
if (fmt == -1) {
if (get_qf_name(mnt, type, QF_VFSV0,
@@ -314,12 +301,12 @@ static int newstate(struct mntent *mnt, int type, char *extra)
NF_FORMAT, &extra) >= 0)
usefmt = QF_VFSOLD;
else {
- errstr(_("Cannot find quota file on %s [%s] to turn quotas on/off.\n"), mnt->mnt_dir, mnt->mnt_fsname);
+ errstr(_("Cannot find quota file on %s [%s] to turn quotas on/off.\n"), mnt->me_dir, mnt->me_devname);
return 1;
}
} else {
if (get_qf_name(mnt, type, fmt, NF_FORMAT, &extra) < 0) {
- errstr(_("Quota file on %s [%s] does not exist or has wrong format.\n"), mnt->mnt_dir, mnt->mnt_fsname);
+ errstr(_("Quota file on %s [%s] does not exist or has wrong format.\n"), mnt->me_dir, mnt->me_devname);
return 1;
}
usefmt = fmt;
@@ -334,23 +321,23 @@ static int newstate(struct mntent *mnt, int type, char *extra)
}
/* Print state of quota (on/off) */
-static int print_state(struct mntent *mnt, int type)
+static int print_state(struct mount_entry *mnt, int type)
{
int on = 0;
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) ||
- !strcmp(mnt->mnt_type, MNTTYPE_GFS2)) {
+ if (!strcmp(mnt->me_type, MNTTYPE_XFS) ||
+ !strcmp(mnt->me_type, MNTTYPE_GFS2)) {
if (kern_qfmt_supp(QF_XFS))
- on = kern_quota_on(mnt->mnt_fsname, type, QF_XFS) != -1;
+ on = kern_quota_on(mnt, type, QF_XFS) != -1;
}
else if (kernel_iface == IFACE_GENERIC)
- on = kern_quota_on(mnt->mnt_fsname, type, -1) != -1;
+ on = kern_quota_on(mnt, type, -1) != -1;
else if (kern_qfmt_supp(QF_VFSV0))
- on = kern_quota_on(mnt->mnt_fsname, type, QF_VFSV0) != -1;
+ on = kern_quota_on(mnt, type, QF_VFSV0) != -1;
else if (kern_qfmt_supp(QF_VFSOLD))
- on = kern_quota_on(mnt->mnt_fsname, type, QF_VFSOLD) != -1;
+ on = kern_quota_on(mnt, type, QF_VFSOLD) != -1;
- printf(_("%s quota on %s (%s) is %s\n"), type2name(type), mnt->mnt_dir, mnt->mnt_fsname,
+ printf(_("%s quota on %s (%s) is %s\n"), type2name(type), mnt->me_dir, mnt->me_devname,
on ? _("on") : _("off"));
return on;
@@ -358,7 +345,7 @@ static int print_state(struct mntent *mnt, int type)
int main(int argc, char **argv)
{
- struct mntent *mnt;
+ struct mount_entry *mnt;
int errs = 0;
gettexton();
@@ -380,9 +367,9 @@ int main(int argc, char **argv)
if (init_mounts_scan(mntcnt, mntpoints, MS_XFS_DISABLED | MS_LOCALONLY) < 0)
return 1;
while ((mnt = get_next_mount())) {
- if (nfs_fstype(mnt->mnt_type)) {
+ if (nfs_fstype(mnt->me_type)) {
if (!(flags & FL_ALL))
- errstr(_("%s: Quota cannot be turned on on NFS filesystem\n"), mnt->mnt_fsname);
+ errstr(_("%s: Quota cannot be turned on on NFS filesystem\n"), mnt->me_devname);
continue;
}
diff --git a/quotaon.h b/quotaon.h
index baf3246..3e449ba 100644
--- a/quotaon.h
+++ b/quotaon.h
@@ -14,6 +14,6 @@
#define STATEFLAG_OFF 0x02
#define STATEFLAG_ALL 0x04
-typedef int (newstate_t) (struct mntent * mnt, int type, char *file, int flags);
-extern int xfs_newstate(struct mntent *mnt, int type, char *file, int flags);
+typedef int (newstate_t) (struct mount_entry * mnt, int type, char *file, int flags);
+extern int xfs_newstate(struct mount_entry *mnt, int type, char *file, int flags);
extern int pinfo(char *fmt, ...);
diff --git a/quotaon_xfs.c b/quotaon_xfs.c
index 0028a88..a271e71 100644
--- a/quotaon_xfs.c
+++ b/quotaon_xfs.c
@@ -22,7 +22,7 @@
* Ensure we don't attempt to go into a dodgey state.
*/
-static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothack, int xopts)
+static int xfs_state_check(int qcmd, int type, int flags, const char *dev, int roothack, int xopts)
{
struct xfs_mem_dqinfo info;
int state;
@@ -132,7 +132,7 @@ static int xfs_state_check(int qcmd, int type, int flags, char *dev, int roothac
return -1;
}
-static int xfs_onoff(char *dev, int type, int flags, int roothack, int xopts)
+static int xfs_onoff(const char *dev, int type, int flags, int roothack, int xopts)
{
int qoff, qcmd, check;
@@ -153,7 +153,7 @@ static int xfs_onoff(char *dev, int type, int flags, int roothack, int xopts)
return 0;
}
-static int xfs_delete(char *dev, int type, int flags, int roothack, int xopts)
+static int xfs_delete(const char *dev, int type, int flags, int roothack, int xopts)
{
int qcmd, check;
@@ -178,15 +178,11 @@ static int xfs_delete(char *dev, int type, int flags, int roothack, int xopts)
* root filesystem.
* We are passed in the new requested state through "type" & "xarg".
*/
-int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags)
+int xfs_newstate(struct mount_entry *mnt, int type, char *xarg, int flags)
{
int err = 1;
int xopts = 0;
int roothack = 0;
- const char *dev = get_device_name(mnt->mnt_fsname);
-
- if (!dev)
- return err;
#ifdef XFS_ROOTHACK
/*
@@ -194,11 +190,11 @@ int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags)
* hack to allow enabling quota on the root filesystem without
* having to specify it at mount time.
*/
- if ((strcmp(mnt->mnt_dir, "/") == 0)) {
+ if ((strcmp(mnt->me_dir, "/") == 0)) {
struct xfs_mem_dqinfo info;
u_int16_t sbflags = 0;
- if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info))
+ if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), mnt->me_devname, 0, (void *)&info))
sbflags = (info.qs_flags & 0xff00) >> 8;
if ((type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT)) &&
@@ -210,22 +206,21 @@ int xfs_newstate(struct mntent *mnt, int type, char *xarg, int flags)
if (xarg == NULL) { /* only enfd on/off */
xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD :
XFS_QUOTA_GDQ_ENFD;
- err = xfs_onoff((char *)dev, type, flags, roothack, xopts);
+ err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts);
}
else if (strcmp(xarg, "account") == 0) {
xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ACCT : XFS_QUOTA_GDQ_ACCT;
- err = xfs_onoff((char *)dev, type, flags, roothack, xopts);
+ err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts);
}
else if (strcmp(xarg, "enforce") == 0) {
xopts |= (type == USRQUOTA) ? XFS_QUOTA_UDQ_ENFD : XFS_QUOTA_GDQ_ENFD;
- err = xfs_onoff((char *)dev, type, flags, roothack, xopts);
+ err = xfs_onoff(mnt->me_devname, type, flags, roothack, xopts);
}
else if (strcmp(xarg, "delete") == 0) {
xopts |= (type == USRQUOTA) ? XFS_USER_QUOTA : XFS_GROUP_QUOTA;
- err = xfs_delete((char *)dev, type, flags, roothack, xopts);
+ err = xfs_delete(mnt->me_devname, type, flags, roothack, xopts);
}
else
die(1, _("Invalid argument \"%s\"\n"), xarg);
- free((char *)dev);
return err;
}
diff --git a/quotasys.c b/quotasys.c
index 16b59a6..73a0799 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -242,7 +242,7 @@ char *fmt2name(int fmt)
/*
* Convert kernel to utility quota format number
*/
-int kern2utilfmt(int kernfmt)
+static int kern2utilfmt(int kernfmt)
{
switch (kernfmt) {
case QFMT_VFS_OLD:
@@ -385,41 +385,27 @@ void number2str(unsigned long long num, char *buf, int format)
}
/*
+ * Wrappers for mount options processing functions
+ */
+
+/*
* Check for XFS filesystem with quota accounting enabled
*/
-static int hasxfsquota(struct mntent *mnt, int type, int flags)
+static int hasxfsquota(const char *dev, struct mntent *mnt, int type, int flags)
{
- int ret = 0;
u_int16_t sbflags;
struct xfs_mem_dqinfo info;
- const char *dev;
- char *opt, *endopt;
if (flags & MS_XFS_DISABLED)
- return 1;
-
- dev = get_device_name(mnt->mnt_fsname);
- if (!dev)
- return 0;
- /* Loopback mounted device with a loopback device in the arguments? */
- if ((opt = hasmntopt(mnt, MNTOPT_LOOP)) && (opt = strchr(opt, '='))) {
- free((char *)dev);
- endopt = strchr(opt+1, ',');
- if (!endopt)
- dev = strdup(opt+1);
- else
- dev = strndup(opt+1, endopt-opt-1);
- if (!dev)
- return 0;
- }
+ return QF_XFS;
memset(&info, 0, sizeof(struct xfs_mem_dqinfo));
if (!quotactl(QCMD(Q_XFS_GETQSTAT, type), dev, 0, (void *)&info)) {
sbflags = (info.qs_flags & 0xff00) >> 8;
if (type == USRQUOTA && (info.qs_flags & XFS_QUOTA_UDQ_ACCT))
- ret = 1;
+ return QF_XFS;
else if (type == GRPQUOTA && (info.qs_flags & XFS_QUOTA_GDQ_ACCT))
- ret = 1;
+ return QF_XFS;
#ifdef XFS_ROOTHACK
/*
* Old XFS filesystems (up to XFS 1.2 / Linux 2.5.47) had a
@@ -427,21 +413,58 @@ static int hasxfsquota(struct mntent *mnt, int type, int flags)
* having to specify it at mount time.
*/
else if (strcmp(mnt->mnt_dir, "/"))
- ret = 0;
+ return QF_ERROR;
else if (type == USRQUOTA && (sbflags & XFS_QUOTA_UDQ_ACCT))
- ret = 1;
+ return QF_XFS;
else if (type == GRPQUOTA && (sbflags & XFS_QUOTA_GDQ_ACCT))
- ret = 1;
+ return QF_XFS;
#endif /* XFS_ROOTHACK */
}
- free((char *)dev);
- return ret;
+
+ return QF_ERROR;
+}
+
+static int hasvfsmetaquota(const char *dev, struct mntent *mnt, int type, int flags)
+{
+ uint32_t fmt;
+
+ if (!quotactl(QCMD(Q_GETFMT, type), dev, 0, (void *)&fmt))
+ return QF_META;
+ return QF_ERROR;
+}
+
+/* Return pointer to given mount option in mount option string */
+char *str_hasmntopt(const char *optstring, const char *opt)
+{
+ const char *p = optstring;
+ const char *s;
+ int len = strlen(opt);
+
+ do {
+ s = p;
+ while (*p && *p != ',' && *p != '=')
+ p++;
+ /* Found option? */
+ if (p - s == len && !strncmp(s, opt, len))
+ return (char *)s;
+ /* Skip mount option argument if there's any */
+ if (*p == '=') {
+ p++;
+ while (*p && *p != ',')
+ p++;
+ }
+ /* Skip separating ',' */
+ if (*p)
+ p++;
+ } while (*p);
+
+ return NULL;
}
/* Return if given option has nonempty argument */
-char *hasmntoptarg(struct mntent *mnt, char *opt)
+static char *hasmntoptarg(const char *optstring, const char *opt)
{
- char *p = hasmntopt(mnt, opt);
+ char *p = str_hasmntopt(optstring, opt);
if (!p)
return NULL;
@@ -451,27 +474,52 @@ char *hasmntoptarg(struct mntent *mnt, char *opt)
return NULL;
}
+/* Copy out mount option argument to a buffer */
+static void copy_mntoptarg(char *buf, const char *optarg, int buflen)
+{
+ char *sep = strchr(optarg, ',');
+
+ if (!sep)
+ sstrncpy(buf, optarg, min(buflen, strlen(optarg) + 1));
+ else
+ sstrncpy(buf, optarg, min(buflen, sep - optarg + 1));
+}
+
/*
* Check to see if a particular quota is to be enabled (filesystem mounted with proper option)
*/
-int hasquota(struct mntent *mnt, int type, int flags)
+static int hasquota(const char *dev, struct mntent *mnt, int type, int flags)
{
- if (hasmntopt(mnt, MNTOPT_NOQUOTA))
- return 0;
-
if (!strcmp(mnt->mnt_type, MNTTYPE_GFS2) ||
!strcmp(mnt->mnt_type, MNTTYPE_XFS))
- return hasxfsquota(mnt, type, flags);
- if (nfs_fstype(mnt->mnt_type)) /* NFS always has quota or better there is no good way how to detect it */
- return 1;
-
- if ((type == USRQUOTA) && (hasmntopt(mnt, MNTOPT_USRQUOTA) || hasmntoptarg(mnt, MNTOPT_USRJQUOTA)))
- return 1;
- if ((type == GRPQUOTA) && (hasmntopt(mnt, MNTOPT_GRPQUOTA) || hasmntoptarg(mnt, MNTOPT_GRPJQUOTA)))
- return 1;
+ return hasxfsquota(dev, mnt, type, flags);
+ if (!strcmp(mnt->mnt_type, MNTTYPE_OCFS2))
+ return hasvfsmetaquota(dev, mnt, type, flags);
+ /*
+ * For ext4 we check whether it has quota in system files and if not,
+ * we fall back on checking standard quotas. Furthermore we cannot use
+ * standard GETFMT quotactl because that does not distinguish between
+ * quota in system file and quota in ordinary file.
+ */
+ if (!strcmp(mnt->mnt_type, MNTTYPE_EXT4)) {
+ struct if_dqinfo kinfo;
+
+ if (quotactl(QCMD(Q_GETINFO, type), dev, 0, (void *)&kinfo) == 0) {
+ if (kinfo.dqi_flags & DQF_SYS_FILE)
+ return QF_META;
+ }
+ }
+ /* NFS always has quota or better there is no good way how to detect it */
+ if (nfs_fstype(mnt->mnt_type))
+ return QF_RPC;
+
+ if ((type == USRQUOTA) && (hasmntopt(mnt, MNTOPT_USRQUOTA) || hasmntoptarg(mnt->mnt_opts, MNTOPT_USRJQUOTA)))
+ return QF_VFSUNKNOWN;
+ if ((type == GRPQUOTA) && (hasmntopt(mnt, MNTOPT_GRPQUOTA) || hasmntoptarg(mnt->mnt_opts, MNTOPT_GRPJQUOTA)))
+ return QF_VFSUNKNOWN;
if ((type == USRQUOTA) && hasmntopt(mnt, MNTOPT_QUOTA))
- return 1;
- return 0;
+ return QF_VFSUNKNOWN;
+ return -1;
}
/* Check whether quotafile for given format exists - return its name in namebuf */
@@ -513,36 +561,36 @@ static int check_fmtfile_ok(char *name, int type, int fmt, int flags)
* otherwise return -1.
* Note that formats without quotafile *must* be detected prior to calling this function
*/
-int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename)
+int get_qf_name(struct mount_entry *mnt, int type, int fmt, int flags, char **filename)
{
char *option, *pathname, has_quota_file_definition = 0;
char qfullname[PATH_MAX];
qfullname[0] = 0;
- if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_USRQUOTA))) {
+ if (type == USRQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_USRQUOTA))) {
if (*(pathname = option + strlen(MNTOPT_USRQUOTA)) == '=')
has_quota_file_definition = 1;
}
- else if (type == USRQUOTA && (option = hasmntoptarg(mnt, MNTOPT_USRJQUOTA))) {
+ else if (type == USRQUOTA && (option = hasmntoptarg(mnt->me_opts, MNTOPT_USRJQUOTA))) {
pathname = option;
has_quota_file_definition = 1;
- sstrncpy(qfullname, mnt->mnt_dir, sizeof(qfullname));
+ sstrncpy(qfullname, mnt->me_dir, sizeof(qfullname));
sstrncat(qfullname, "/", sizeof(qfullname));
}
- else if (type == GRPQUOTA && (option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) {
+ else if (type == GRPQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_GRPQUOTA))) {
pathname = option + strlen(MNTOPT_GRPQUOTA);
if (*pathname == '=') {
has_quota_file_definition = 1;
pathname++;
}
}
- else if (type == GRPQUOTA && (option = hasmntoptarg(mnt, MNTOPT_GRPJQUOTA))) {
+ else if (type == GRPQUOTA && (option = hasmntoptarg(mnt->me_opts, MNTOPT_GRPJQUOTA))) {
pathname = option;
has_quota_file_definition = 1;
- sstrncpy(qfullname, mnt->mnt_dir, sizeof(qfullname));
+ sstrncpy(qfullname, mnt->me_dir, sizeof(qfullname));
sstrncat(qfullname, "/", sizeof(qfullname));
}
- else if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_QUOTA))) {
+ else if (type == USRQUOTA && (option = str_hasmntopt(mnt->me_opts, MNTOPT_QUOTA))) {
pathname = option + strlen(MNTOPT_QUOTA);
if (*pathname == '=') {
has_quota_file_definition = 1;
@@ -553,14 +601,11 @@ int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filenam
return -1;
if (has_quota_file_definition) {
- if ((option = strchr(pathname, ','))) {
- int tocopy = min(option - pathname + 1,
- sizeof(qfullname) - strlen(qfullname));
- sstrncpy(qfullname + strlen(qfullname), pathname, tocopy);
- } else
- sstrncat(qfullname, pathname, sizeof(qfullname));
+ int len = strlen(qfullname);
+
+ copy_mntoptarg(qfullname + len, pathname, sizeof(qfullname) - len);
} else {
- snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->mnt_dir,
+ snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->me_dir,
basenames[fmt], extensions[type]);
}
if (check_fmtfile_ok(qfullname, type, fmt, flags)) {
@@ -579,7 +624,7 @@ int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filenam
struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt,
int ioflags, int mntflags)
{
- struct mntent *mnt;
+ struct mount_entry *mnt;
int gotmnt = 0;
static int hlist_allocated = 0;
static struct quota_handle **hlist = NULL;
@@ -613,18 +658,18 @@ add_entry:
else {
switch (fmt) {
case QF_RPC:
- if (nfs_fstype(mnt->mnt_type))
+ if (nfs_fstype(mnt->me_type))
goto add_entry;
break;
case QF_XFS:
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS) ||
- !strcmp(mnt->mnt_type, MNTTYPE_GFS2))
+ if (!strcmp(mnt->me_type, MNTTYPE_XFS) ||
+ !strcmp(mnt->me_type, MNTTYPE_GFS2))
goto add_entry;
break;
default:
- if (strcmp(mnt->mnt_type, MNTTYPE_XFS) &&
- strcmp(mnt->mnt_type, MNTTYPE_GFS2) &&
- !nfs_fstype(mnt->mnt_type))
+ if (strcmp(mnt->me_type, MNTTYPE_XFS) &&
+ strcmp(mnt->me_type, MNTTYPE_GFS2) &&
+ !nfs_fstype(mnt->me_type))
goto add_entry;
break;
}
@@ -818,13 +863,30 @@ static int xfs_kern_quota_on(const char *dev, int type)
/*
* Check whether is quota turned on on given device for given type
*/
-int kern_quota_on(const char *dev, int type, int fmt)
+int kern_quota_on(struct mount_entry *mnt, int type, int fmt)
{
+ if (mnt->me_qfmt[type] < 0)
+ return -1;
+ if (fmt == QF_RPC)
+ return -1;
+ if (mnt->me_qfmt[type] == QF_XFS) {
+ if ((fmt == -1 || fmt == QF_XFS) &&
+ xfs_kern_quota_on(mnt->me_devname, type)) /* XFS quota format */
+ return QF_XFS;
+ return -1;
+ }
+ /* No more chances for XFS format to succeed... */
+ if (fmt == QF_XFS)
+ return -1;
+ /* Meta format is always enabled */
+ if (mnt->me_qfmt[type] == QF_META)
+ return QF_META;
+
/* Check whether quota is turned on... */
if (kernel_iface == IFACE_GENERIC) {
int actfmt;
- if (quotactl(QCMD(Q_GETFMT, type), dev, 0,
+ if (quotactl(QCMD(Q_GETFMT, type), mnt->me_devname, 0,
(void *)&actfmt) >= 0) {
actfmt = kern2utilfmt(actfmt);
if (actfmt >= 0)
@@ -832,15 +894,12 @@ int kern_quota_on(const char *dev, int type, int fmt)
}
} else {
if ((fmt == -1 || fmt == QF_VFSV0) &&
- v2_kern_quota_on(dev, type)) /* VFSv0 quota format */
+ v2_kern_quota_on(mnt->me_devname, type))
return QF_VFSV0;
if ((fmt == -1 || fmt == QF_VFSOLD) &&
- v1_kern_quota_on(dev, type)) /* Old quota format */
+ v1_kern_quota_on(mnt->me_devname, type))
return QF_VFSOLD;
}
- if ((fmt == -1 || fmt == QF_XFS) &&
- xfs_kern_quota_on(dev, type)) /* XFS quota format */
- return QF_XFS;
return -1;
}
@@ -850,15 +909,6 @@ int kern_quota_on(const char *dev, int type, int fmt)
*
*/
-struct mount_entry {
- char *me_type; /* Type of filesystem for given entry */
- char *me_opts; /* Options of filesystem */
- dev_t me_dev; /* Device filesystem is mounted on */
- ino_t me_ino; /* Inode number of root of filesystem */
- const char *me_devname; /* Name of device (after pass through get_device_name()) */
- const char *me_dir; /* One of mountpoints of filesystem */
-};
-
struct searched_dir {
int sd_dir; /* Is searched dir mountpoint or in fact device? */
dev_t sd_dev; /* Device mountpoint lies on */
@@ -906,6 +956,8 @@ alloc:
allocated += ALLOC_ENTRIES_NUM;
while ((mnt = getmntent(mntf))) {
const char *devname;
+ char *opt;
+ int qfmt[MAXQUOTAS];
if (!(devname = get_device_name(mnt->mnt_fsname))) {
errstr(_("Cannot get device name for %s\n"), mnt->mnt_fsname);
@@ -936,10 +988,27 @@ alloc:
free((char *)devname);
continue;
}
+ if (hasmntopt(mnt, MNTOPT_NOQUOTA)) {
+ free((char *)devname);
+ continue;
+ }
+ if (hasmntopt(mnt, MNTOPT_BIND)) {
+ free((char *)devname);
+ continue; /* We just ignore bind mounts... */
+ }
+ if ((opt = hasmntoptarg(mnt->mnt_opts, MNTOPT_LOOP))) {
+ char loopdev[PATH_MAX];
+
+ copy_mntoptarg(opt, loopdev, PATH_MAX);
+ free((char *)devname);
+ devname = sstrdup(loopdev);
+ }
/* Further we are not interested in mountpoints without quotas and
we don't want to touch them */
- if (!hasquota(mnt, USRQUOTA, flags) && !hasquota(mnt, GRPQUOTA, flags)) {
+ qfmt[USRQUOTA] = hasquota(devname, mnt, USRQUOTA, flags);
+ qfmt[GRPQUOTA] = hasquota(devname, mnt, GRPQUOTA, flags);
+ if (qfmt[USRQUOTA] < 0 && qfmt[GRPQUOTA] < 0) {
free((char *)devname);
continue;
}
@@ -967,50 +1036,12 @@ alloc:
free((char *)devname);
continue;
}
- if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
- unsupporteddev:
+ if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode)) {
errstr(_("Device (%s) filesystem is mounted on unsupported device type. Skipping.\n"), devname);
free((char *)devname);
continue;
- } else {
- char *opt;
-
- if (hasmntopt(mnt, MNTOPT_BIND)) {
- free((char *)devname);
- continue; /* We just ignore bind mounts... */
- }
- else if ((opt = hasmntopt(mnt, MNTOPT_LOOP))) {
- char loopdev[PATH_MAX];
- int i;
-
- if (!(opt = strchr(opt, '='))) {
- errstr(_("Cannot find device of loopback mount in options for %s. Skipping.\n"), devname);
- free((char *)devname);
- continue;
- }
- /* Copy the device name */
- for (opt++, i = 0; *opt && i < sizeof(loopdev)-1 && *opt != ','; opt++, i++)
- loopdev[i] = *opt;
- loopdev[i] = 0;
- if (stat(loopdev, &st) < 0) { /* Can't stat loopback device? */
- errstr(_("Cannot stat() loopback device %s: %s\n"), opt, strerror(errno));
- free((char *)devname);
- continue;
- }
- if (!S_ISBLK(st.st_mode)) {
- errstr(_("Loopback device %s is not block device!\n"), opt);
- free((char *)devname);
- continue;
- }
- dev = st.st_rdev;
- free((char *)devname);
- devname = sstrdup(loopdev);
- } else {
- if (!S_ISBLK(st.st_mode) && !S_ISCHR(st.st_mode))
- goto unsupporteddev;
- dev = st.st_rdev;
- }
}
+ dev = st.st_rdev;
for (i = 0; i < mnt_entries_cnt && mnt_entries[i].me_dev != dev; i++);
}
/* Cope with network filesystems or new mountpoint */
@@ -1040,7 +1071,9 @@ alloc:
mnt_entries[i].me_dev = dev;
mnt_entries[i].me_ino = st.st_ino;
mnt_entries[i].me_devname = devname;
- mnt_entries[i].me_dir = sstrdup(mntpointbuf);
+ mnt_entries[i].me__dir = sstrdup(mntpointbuf);
+ mnt_entries[i].me_dir = NULL;
+ memcpy(&mnt_entries[i].me_qfmt, qfmt, sizeof(qfmt));
mnt_entries_cnt++;
}
else
@@ -1059,7 +1092,7 @@ static const char *find_dir_mntpoint(struct stat *st)
for (i = 0; i < mnt_entries_cnt; i++)
if (mnt_entries[i].me_dev == st->st_dev) {
st->st_ino = mnt_entries[i].me_ino;
- return mnt_entries[i].me_dir;
+ return mnt_entries[i].me__dir;
}
return NULL;
}
@@ -1122,7 +1155,7 @@ static int process_dirs(int dcnt, char **dirs, int flags)
errstr(_("Cannot find mountpoint for device %s\n"), dirs[i]);
continue;
}
- sstrncpy(mntpointbuf, mnt_entries[mentry].me_dir, PATH_MAX-1);
+ sstrncpy(mntpointbuf, mnt_entries[mentry].me__dir, PATH_MAX-1);
}
else {
errstr(_("Specified path %s is not directory nor device.\n"), dirs[i]);
@@ -1158,14 +1191,8 @@ int init_mounts_scan(int dcnt, char **dirs, int flags)
/* Find next usable mountpoint when scanning all mountpoints */
static int find_next_entry_all(int *pos)
{
- struct mntent mnt;
-
while (++act_checked < mnt_entries_cnt) {
- mnt.mnt_fsname = (char *)mnt_entries[act_checked].me_devname;
- mnt.mnt_type = mnt_entries[act_checked].me_type;
- mnt.mnt_opts = mnt_entries[act_checked].me_opts;
- mnt.mnt_dir = (char *)mnt_entries[act_checked].me_dir;
- if (!hasmntopt(&mnt, MNTOPT_NOAUTO))
+ if (!str_hasmntopt(mnt_entries[act_checked].me_opts, MNTOPT_NOAUTO))
break;
}
if (act_checked >= mnt_entries_cnt)
@@ -1204,25 +1231,21 @@ restart:
/*
* Return next directory from the list
*/
-struct mntent *get_next_mount(void)
+struct mount_entry *get_next_mount(void)
{
- static struct mntent mnt;
int mntpos;
if (!check_dirs_cnt) { /* Scan all mountpoints? */
if (!find_next_entry_all(&mntpos))
return NULL;
- mnt.mnt_dir = (char *)mnt_entries[mntpos].me_dir;
+ mnt_entries[mntpos].me_dir = mnt_entries[mntpos].me__dir;
}
else {
if (!find_next_entry_sel(&mntpos))
return NULL;
- mnt.mnt_dir = (char *)check_dirs[act_checked].sd_name;
+ mnt_entries[mntpos].me_dir = check_dirs[act_checked].sd_name;
}
- mnt.mnt_fsname = (char *)mnt_entries[mntpos].me_devname;
- mnt.mnt_type = mnt_entries[mntpos].me_type;
- mnt.mnt_opts = mnt_entries[mntpos].me_opts;
- return &mnt;
+ return &mnt_entries[mntpos];
}
/*
@@ -1236,7 +1259,7 @@ void end_mounts_scan(void)
free(mnt_entries[i].me_type);
free(mnt_entries[i].me_opts);
free((char *)mnt_entries[i].me_devname);
- free((char *)mnt_entries[i].me_dir);
+ free((char *)mnt_entries[i].me__dir);
}
free(mnt_entries);
mnt_entries = NULL;
diff --git a/quotasys.h b/quotasys.h
index 005b275..1cebf7e 100644
--- a/quotasys.h
+++ b/quotasys.h
@@ -36,6 +36,17 @@
/* Supported kernel interface */
extern int kernel_iface;
+struct mount_entry {
+ char *me_type; /* Type of filesystem for given entry */
+ char *me_opts; /* Options of filesystem */
+ dev_t me_dev; /* Device filesystem is mounted on */
+ ino_t me_ino; /* Inode number of root of filesystem */
+ const char *me_devname; /* Name of device (after pass through get_device_name()) */
+ const char *me__dir; /* One mountpoint of a filesystem (strdup()ed) */
+ const char *me_dir; /* Current mountpoint of a filesystem to process */
+ int me_qfmt[MAXQUOTAS]; /* Detected quota formats */
+};
+
/*
* Exported functions
*/
@@ -95,18 +106,23 @@ void space2str(qsize_t, char *, int);
/* Convert number to short printable form */
void number2str(unsigned long long, char *, int);
-/* Check to see if particular quota is to be enabled */
-/* Recognizes MS_XFS_DISABLED flag */
-int hasquota(struct mntent *mnt, int type, int flags);
+/* Return pointer to given mount option in mount option string */
+char *str_hasmntopt(const char *optstring, const char *opt);
+
+/* Check to see if particular quota type is configured */
+static inline int me_hasquota(struct mount_entry *mnt, int type)
+{
+ return mnt->me_qfmt[type] >= 0;
+}
/* Flags for get_qf_name() */
#define NF_EXIST 1 /* Check whether file exists */
#define NF_FORMAT 2 /* Check whether file is in proper format */
/* Get quotafile name for given entry */
-int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename);
+int get_qf_name(struct mount_entry *mnt, int type, int fmt, int flags, char **filename);
/* Detect newest quota format with existing file */
-int detect_quota_files(struct mntent *mnt, int type, int fmt);
+int detect_quota_files(struct mount_entry *mnt, int type, int fmt);
/* Create NULL-terminated list of handles for quotafiles for given mountpoints */
struct quota_handle **create_handle_list(int count, char **mntpoints, int type, int fmt,
@@ -124,7 +140,7 @@ int devcmp_handles(struct quota_handle *a, struct quota_handle *b);
void init_kernel_interface(void);
/* Check whether is quota turned on on given device for given type */
-int kern_quota_on(const char *dev, int type, int fmt);
+int kern_quota_on(struct mount_entry *mnt, int type, int fmt);
/* Return whether kernel is able to handle given format */
int kern_qfmt_supp(int fmt);
@@ -141,7 +157,7 @@ int kern_qfmt_supp(int fmt);
int init_mounts_scan(int dcnt, char **dirs, int flags);
/* Return next mountpoint for scan */
-struct mntent *get_next_mount(void);
+struct mount_entry *get_next_mount(void);
/* Free all structures associated with mountpoints scan */
void end_mounts_scan(void);
diff --git a/rquota_server.c b/rquota_server.c
index 3293de7..bb270e6 100644
--- a/rquota_server.c
+++ b/rquota_server.c
@@ -147,7 +147,7 @@ setquota_rslt *setquotainfo(int lflags, caddr_t * argp, struct svc_req *rqstp)
} arguments;
struct util_dqblk dqblk;
struct dquot *dquot;
- struct mntent *mnt;
+ struct mount_entry *mnt;
char pathname[PATH_MAX] = {0};
char *pathp = pathname;
int id, qcmd, type;
@@ -239,7 +239,7 @@ getquota_rslt *getquotainfo(int lflags, caddr_t * argp, struct svc_req * rqstp)
ext_getquota_args *ext_args;
} arguments;
struct dquot *dquot = NULL;
- struct mntent *mnt;
+ struct mount_entry *mnt;
char pathname[PATH_MAX] = {0};
char *pathp = pathname;
int id, type;