summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjkar8572 <jkar8572>2002-03-27 16:21:26 +0000
committerjkar8572 <jkar8572>2002-03-27 16:21:26 +0000
commit5975341695e27f23f5a58758954d1ea31c2d0d25 (patch)
tree5bb3bac1bdc313edffa6552867c8954a5dfeaac7
parenta40b9d8688fe0f1f34c70a986d3e408273fed14e (diff)
downloadlinuxquota-5975341695e27f23f5a58758954d1ea31c2d0d25.tar.gz
Fixed bug in quota(1) return code.
Rewritten detection of kernel version. Added support for generic interface for both quota formats in kernel.
-rw-r--r--Changelog5
-rw-r--r--Makefile.in6
-rw-r--r--convertquota.c15
-rw-r--r--edquota.c5
-rw-r--r--quota.c16
-rw-r--r--quota.h66
-rw-r--r--quotacheck.c40
-rw-r--r--quotaio.c64
-rw-r--r--quotaio.h9
-rw-r--r--quotaio_rpc.c9
-rw-r--r--quotaio_v1.c114
-rw-r--r--quotaio_v2.c159
-rw-r--r--quotaio_v2.h2
-rw-r--r--quotaon.816
-rw-r--r--quotaon.c300
-rw-r--r--quotaon.h1
-rw-r--r--quotastats.c7
-rw-r--r--quotasys.c209
-rw-r--r--quotasys.h29
-rw-r--r--repquota.c8
-rw-r--r--rquota_svc.c5
-rw-r--r--setquota.c2
-rw-r--r--warnquota.82
-rw-r--r--warnquota.c10
24 files changed, 673 insertions, 426 deletions
diff --git a/Changelog b/Changelog
index 5724fbb..7460bde 100644
--- a/Changelog
+++ b/Changelog
@@ -1,3 +1,8 @@
+Changes in quota-tools from 3.04 to 3.05
+* added support for quota 6.5.1 (Jan Kara)
+* quotaon(8) now can get format parameter (Jan Kara)
+* fixed bad return value of quota(1) (Jan Kara)
+
Changes in quota-tools from 3.03 to 3.04
* added -D_FILE_OFFSET_BITS=64 to Makefile - fixes problems with large files with some libcs (Michael Meskes)
* added -p (print state) to quotaon (Vladimir Linek, Jan Kara)
diff --git a/Makefile.in b/Makefile.in
index 736594c..f6b1a82 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -1,6 +1,6 @@
PROGS = quotacheck quotaon quota quot repquota warnquota quotastats xqmstats edquota setquota convertquota rpc.rquotad
-SOURCES = bylabel.c common.c convertquota.c edquota.c pot.c quot.c quota.c quotacheck.c quotacheck_v1.c quotacheck_v2.c quotaio.c quotaio_rpc.c quotaio_v1.c quotaio_v2.c quotaio_xfs.c quotaon.c quotaon_xfs.c quotaops.c quotastats.c quotasys.c repquota.c rquota_client.c rquota_server.c rquota_svc.c setquota.c warnquota.c xqmstats.c
-VERSIONDEF = -DQUOTA_VERSION=\"3.04\"
+SOURCES = bylabel.c common.c convertquota.c edquota.c pot.c quot.c quota.c quotacheck.c quotacheck_v1.c quotacheck_v2.c quotaio.c quotaio_rpc.c quotaio_v1.c quotaio_v2.c quotaio_xfs.c quotaio_generic.c quotaon.c quotaon_xfs.c quotaops.c quotastats.c quotasys.c repquota.c rquota_client.c rquota_server.c rquota_svc.c setquota.c warnquota.c xqmstats.c
+VERSIONDEF = -DQUOTA_VERSION=\"3.05\"
CFLAGS = @CFLAGS@ @EXT2_DIRECT@ -D_GNU_SOURCE -Wall -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 $(VERSIONDEF)
EXT2LIBS = @EXT2LIBS@
RPCSRC = rquota.h rquota_xdr.c rquota_clnt.c
@@ -33,7 +33,7 @@ root_sbindir = /sbin
locale_dir = $(prefix)/share/locale
RPCCLNTOBJS = rquota_xdr.o rquota_client.o rquota_clnt.o
-IOOBJS = quotaio.o quotaio_v1.o quotaio_v2.o quotaio_rpc.o quotaio_xfs.o
+IOOBJS = quotaio.o quotaio_v1.o quotaio_v2.o quotaio_rpc.o quotaio_xfs.o quotaio_generic.o
IOOBJS += $(RPCCLNTOBJS)
LIBOBJS = bylabel.o common.o quotasys.o pot.o $(IOOBJS)
LIBOBJS += @LIBMALLOC@
diff --git a/convertquota.c b/convertquota.c
index 5106a88..f690889 100644
--- a/convertquota.c
+++ b/convertquota.c
@@ -42,15 +42,8 @@ static void usage(void)
static void parse_options(int argcnt, char **argstr)
{
int ret;
- char *slash = strrchr(argstr[0], '/'), cmdname[PATH_MAX];
-
- if (!slash)
- slash = argstr[0];
- else
- slash++;
action = ACT_FORMAT;
- sstrncpy(cmdname, slash, sizeof(cmdname));
while ((ret = getopt(argcnt, argstr, "Vugefh:")) != -1) {
switch (ret) {
case '?':
@@ -253,7 +246,10 @@ static int rename_file(int type, struct mntent *mnt)
char *qfname, namebuf[PATH_MAX];
int ret = 0;
- qfname = get_qf_name(mnt, type, QF_VFSV0);
+ if (get_qf_name(mnt, type, (1 << QF_VFSV0), 0, &qfname) < 0) {
+ errstr(_("Can't get name of new quotafile.\n"));
+ return -1;
+ }
strcpy(namebuf, qfname);
sstrncat(namebuf, ".new", sizeof(namebuf));
if (rename(namebuf, qfname) < 0) {
@@ -296,7 +292,7 @@ static int convert_endian(int type, struct mntent *mnt)
int ofd;
char *qfname;
- if (!(qfname = get_qf_name(mnt, type, QF_VFSV0)))
+ if (get_qf_name(mnt, type, (1 << QF_VFSV0), NF_EXIST, &qfname) < 0)
return -1;
if ((ofd = open(qfname, O_RDONLY)) < 0) {
errstr(_("Can't open old quota file on %s: %s\n"), mnt->mnt_dir, strerror(errno));
@@ -348,6 +344,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
parse_options(argc, argv);
+ init_kernel_interface();
if (init_mounts_scan(1, &mntpoint) < 0)
return 1;
if (!(mnt = get_next_mount(0))) {
diff --git a/edquota.c b/edquota.c
index 5f44905..f82a3a3 100644
--- a/edquota.c
+++ b/edquota.c
@@ -34,7 +34,7 @@
#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $"
#ident "$Copyright: All rights reserved. $"
-#ident "$Id: edquota.c,v 1.7 2001/12/14 08:17:02 jkar8572 Exp $"
+#ident "$Id: edquota.c,v 1.8 2002/03/27 16:21:26 jkar8572 Exp $"
/*
* Disk quota editor.
@@ -141,6 +141,7 @@ int main(int argc, char **argv)
if (tflag && argc != 0)
usage();
+ init_kernel_interface();
handles = create_handle_list(0, dirname ? &dirname : NULL, quotatype, fmt, rflag ? 0 : IOI_LOCALONLY);
if (!handles[0]) {
dispose_handle_list(handles);
@@ -175,7 +176,6 @@ int main(int argc, char **argv)
}
dispose_handle_list(handles);
freeprivs(protoprivs);
- warn_new_kernel(fmt);
exit(0);
}
@@ -224,7 +224,6 @@ int main(int argc, char **argv)
}
}
dispose_handle_list(handles);
- warn_new_kernel(fmt);
close(tmpfd);
unlink(tmpfil);
diff --git a/quota.c b/quota.c
index 37baeaa..06f1167 100644
--- a/quota.c
+++ b/quota.c
@@ -34,7 +34,7 @@
#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $"
#ident "$Copyright: All rights reserved. $"
-#ident "$Id: quota.c,v 1.8 2002/03/05 16:01:24 jkar8572 Exp $"
+#ident "$Id: quota.c,v 1.9 2002/03/27 16:21:26 jkar8572 Exp $"
/*
* Disk quota reporting program.
@@ -107,27 +107,27 @@ int main(int argc, char **argv)
argc -= optind;
argv += optind;
- warn_new_kernel(fmt);
if (!uflag && !gflag)
uflag++;
+ init_kernel_interface();
+ ret = 0;
if (argc == 0) {
if (uflag)
- showquotas(USRQUOTA, getuid());
+ ret |= showquotas(USRQUOTA, getuid());
if (gflag) {
ngroups = getgroups(NGROUPS, gidset);
if (ngroups < 0)
die(1, _("quota: getgroups(): %s\n"), strerror(errno));
for (i = 0; i < ngroups; i++)
- showquotas(GRPQUOTA, gidset[i]);
+ ret |= showquotas(GRPQUOTA, gidset[i]);
}
- exit(0);
+ exit(ret);
}
if (uflag && gflag)
usage();
- ret = 0;
if (uflag)
for (; argc > 0; argc--, argv++)
ret |= showquotas(USRQUOTA, user2uid(*argv));
@@ -169,7 +169,7 @@ int showquotas(int type, qid_t id)
if (q->dq_dqb.dqb_ihardlimit && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_ihardlimit)
msgi = _("File limit reached on");
else if (q->dq_dqb.dqb_isoftlimit
- && q->dq_dqb.dqb_curinodes > q->dq_dqb.dqb_isoftlimit) {
+ && q->dq_dqb.dqb_curinodes >= q->dq_dqb.dqb_isoftlimit) {
if (q->dq_dqb.dqb_itime > now)
msgi = _("In file grace period on");
else {
@@ -182,7 +182,7 @@ int showquotas(int type, qid_t id)
&& toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bhardlimit)
msgb = _("Block limit reached on");
else if (q->dq_dqb.dqb_bsoftlimit
- && toqb(q->dq_dqb.dqb_curspace) > q->dq_dqb.dqb_bsoftlimit) {
+ && toqb(q->dq_dqb.dqb_curspace) >= q->dq_dqb.dqb_bsoftlimit) {
if (q->dq_dqb.dqb_btime > now)
msgb = _("In block grace period on");
else {
diff --git a/quota.h b/quota.h
index 9b4b424..a39a9ae 100644
--- a/quota.h
+++ b/quota.h
@@ -46,9 +46,68 @@ typedef u_int64_t qsize_t; /* Type in which we store size limitations */
#define SUBCMDSHIFT 8
#define QCMD(cmd, type) (((cmd) << SUBCMDSHIFT) | ((type) & SUBCMDMASK))
-#define Q_QUOTAON 0x0100 /* enable quotas */
-#define Q_QUOTAOFF 0x0200 /* disable quotas */
-#define Q_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+#define Q_6_5_QUOTAON 0x0100 /* enable quotas */
+#define Q_6_5_QUOTAOFF 0x0200 /* disable quotas */
+#define Q_6_5_SYNC 0x0600 /* sync disk copy of a filesystems quotas */
+
+#define Q_SYNC 0x800001 /* sync disk copy of a filesystems quotas */
+#define Q_QUOTAON 0x800002 /* turn quotas on */
+#define Q_QUOTAOFF 0x800003 /* turn quotas off */
+#define Q_GETFMT 0x800004 /* get quota format used on given filesystem */
+#define Q_GETINFO 0x800005 /* get information about quota files */
+#define Q_SETINFO 0x800006 /* set information about quota files */
+#define Q_GETQUOTA 0x800007 /* get user quota structure */
+#define Q_SETQUOTA 0x800008 /* set user quota structure */
+
+/*
+ * Quota structure used for communication with userspace via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define QIF_BLIMITS 1
+#define QIF_SPACE 2
+#define QIF_ILIMITS 4
+#define QIF_INODES 8
+#define QIF_BTIME 16
+#define QIF_ITIME 32
+#define QIF_LIMITS (QIF_BLIMITS | QIF_ILIMITS)
+#define QIF_USAGE (QIF_SPACE | QIF_INODES)
+#define QIF_TIMES (QIF_BTIME | QIF_ITIME)
+#define QIF_ALL (QIF_LIMITS | QIF_USAGE | QIF_TIMES)
+
+struct if_dqblk {
+ u_int64_t dqb_bhardlimit;
+ u_int64_t dqb_bsoftlimit;
+ u_int64_t dqb_curspace;
+ u_int64_t dqb_ihardlimit;
+ u_int64_t dqb_isoftlimit;
+ u_int64_t dqb_curinodes;
+ u_int64_t dqb_btime;
+ u_int64_t dqb_itime;
+ u_int32_t dqb_valid;
+};
+
+/*
+ * Structure used for setting quota information about file via quotactl
+ * Following flags are used to specify which fields are valid
+ */
+#define IIF_BGRACE 1
+#define IIF_IGRACE 2
+#define IIF_FLAGS 4
+#define IIF_ALL (IIF_BGRACE | IIF_IGRACE | IIF_FLAGS)
+
+struct if_dqinfo {
+ u_int64_t dqi_bgrace;
+ u_int64_t dqi_igrace;
+ u_int32_t dqi_flags;
+ u_int32_t dqi_valid;
+};
+
+/* Quota format identifiers */
+#define QFMT_VFS_OLD 1
+#define QFMT_VFS_V0 2
+
+/* Flags supported by kernel */
+#define V1_DQF_RSQUASH 1
/* Ioctl for getting quota size */
#include <sys/ioctl.h>
@@ -64,7 +123,6 @@ typedef u_int64_t qsize_t; /* Type in which we store size limitations */
#endif
#endif
-
long quotactl __P((int, const char *, qid_t, caddr_t));
#endif /* _QUOTA_ */
diff --git a/quotacheck.c b/quotacheck.c
index 8a3615f..d5cef50 100644
--- a/quotacheck.c
+++ b/quotacheck.c
@@ -8,7 +8,7 @@
* New quota format implementation - Jan Kara <jack@suse.cz> - Sponsored by SuSE CR
*/
-#ident "$Id: quotacheck.c,v 1.26 2001/12/14 07:50:48 jkar8572 Exp $"
+#ident "$Id: quotacheck.c,v 1.27 2002/03/27 16:21:26 jkar8572 Exp $"
#include <dirent.h>
#include <stdio.h>
@@ -564,13 +564,13 @@ Please turn quotas off or use -f to force checking.\n"),
type2name(type), mnt->mnt_dir);
}
/* At least sync quotas so damage will be smaller */
- if (quotactl(QCMD(Q_SYNC, type), mnt->mnt_fsname, 0, NULL) < 0)
+ 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));
}
- if (!(flags & FL_NEWFILE)) { /* Need to really buffer file? */
- qfname = get_qf_name(mnt, type, cfmt);
- if (!qfname) {
+ if (!(flags & FL_NEWFILE)) { /* Need to buffer file? */
+ if (get_qf_name(mnt, type, (1 << cfmt), NF_EXIST, &qfname) < 0) {
errstr(_("Cannot get quotafile name for %s\n"), mnt->mnt_fsname);
return -1;
}
@@ -617,7 +617,7 @@ static int rename_files(struct mntent *mnt, int type)
mode_t mode = S_IRUSR | S_IWUSR;
debug(FL_DEBUG, _("Data dumped.\n"));
- if (!(filename = get_qf_name(mnt, type, cfmt)))
+ if (get_qf_name(mnt, type, (1 << cfmt), 0, &filename) < 0)
die(2, _("Cannot get name of old quotafile on %s.\n"), mnt->mnt_dir);
if (stat(filename, &st) < 0) { /* File doesn't exist? */
if (errno == ENOENT) {
@@ -704,12 +704,26 @@ static int dump_to_file(struct mntent *mnt, int type)
if (cfmt == kern_quota_on(mnt->mnt_fsname, type, 1 << cfmt)) { /* Quota turned on? */
char *filename;
- filename = get_qf_name(mnt, type, cfmt);
- if (quotactl(QCMD(Q_QUOTAOFF, type), mnt->mnt_fsname, 0, NULL)
- || quotactl(QCMD(Q_QUOTAON, type), mnt->mnt_fsname, 0, filename))
- errstr(_("Cannot turn %s quotas on %s off and on: %s\nKernel won't know about changes quotacheck did.\n"),
- type2name(type), mnt->mnt_fsname, strerror(errno));
- free(filename);
+ if (get_qf_name(mnt, type, 1 << cfmt, NF_FORMAT, &filename) < 0)
+ errstr(_("Cannot find checked quota file for %ss on %s!\n"), type2name(type), mnt->mnt_fsname);
+ else {
+ if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_QUOTAOFF : Q_6_5_QUOTAOFF, type),
+ mnt->mnt_fsname, 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));
+ else {
+ int ret;
+
+ if (kernel_iface == IFACE_GENERIC)
+ ret = quotactl(QCMD(Q_QUOTAON, type), mnt->mnt_fsname, util2kernfmt(cfmt), filename);
+ else
+ ret = quotactl(QCMD(Q_6_5_QUOTAON, type), mnt->mnt_fsname, 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));
+ }
+ free(filename);
+ }
}
return 0;
}
@@ -877,7 +891,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
parse_options(argc, argv);
- warn_new_kernel(fmt);
+ init_kernel_interface();
check_all();
#ifdef DEBUG_MALLOC
diff --git a/quotaio.c b/quotaio.c
index 3efda67..20ff6cb 100644
--- a/quotaio.c
+++ b/quotaio.c
@@ -26,9 +26,6 @@
#include "dqblk_rpc.h"
#include "dqblk_xfs.h"
-static int file_magics[] = INITQMAGICS;
-static int known_versions[] = INITKNOWNVERSIONS;
-
/* Header in all newer quotafiles */
struct disk_dqheader {
u_int32_t dqh_magic;
@@ -36,28 +33,6 @@ struct disk_dqheader {
} __attribute__ ((packed));
/*
- * Detect quotafile format
- */
-int detect_qf_format(int fd, int type)
-{
- struct disk_dqheader head;
- int ret;
-
- if ((ret = read(fd, &head, sizeof(head))) < 0)
- die(2, _("Error while reading from quotafile: %s\n"), strerror(errno));
- if (ret != sizeof(head)) /* Short file? Probably old format */
- return QF_VFSOLD;
- if (__le32_to_cpu(head.dqh_magic) != file_magics[type])
- if (__be32_to_cpu(head.dqh_magic) == file_magics[type])
- die(3, _("Your quota file is stored in wrong endianity. Please use convertquota to convert it.\n"));
- else
- return QF_VFSOLD;
- if (__le32_to_cpu(head.dqh_version) > known_versions[type]) /* Too new format? */
- return QF_TOONEW;
- return QF_VFSV0;
-}
-
-/*
* Detect quota format and initialize quota IO
*/
struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
@@ -107,26 +82,19 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
h->qh_ops->init_io(h);
return h;
}
- kernfmt = kern_quota_format(); /* Check kernel quota format */
- if (kernfmt == QF_TOONEW || kernfmt > 0) {
- /* Try whether some quota isn't turned on */
- if (fmt != -1) {
- if (kern_quota_on(h->qh_quotadev, type, 1 << fmt) != -1)
- h->qh_io_flags |= IOFL_QUOTAON;
- }
- else if (kernfmt == QF_TOONEW) {
- if ((fmt = kern_quota_on(h->qh_quotadev, type, (1 << QF_VFSOLD) | (1 << QF_VFSV0))) != -1)
- h->qh_io_flags |= IOFL_QUOTAON;
+ if (kernel_formats > 0 && (fmt == -1 || (1 << fmt) & kernel_formats)) { /* Quota compiled and desired format available? */
+ /* Quota turned on? */
+ kernfmt = kern_quota_on(h->qh_quotadev, type, fmt == -1 ? kernel_formats : (1 << fmt));
+ if (kernfmt >= 0) {
+ h->qh_io_flags |= IOFL_QUOTAON;
+ fmt = kernfmt; /* Default is kernel used format */
}
- else
- if ((fmt = kern_quota_on(h->qh_quotadev, type, kernfmt)) != -1)
- h->qh_io_flags |= IOFL_QUOTAON;
}
- if (!(qfname = get_qf_name(mnt, type, fmt))) {
- errstr(_("Can't get quotafile name.\n"));
+ if ((fmt = get_qf_name(mnt, type, (fmt == -1) ? ((1 << QF_VFSOLD) | (1 << QF_VFSV0)) : (1 << fmt), NF_FORMAT, &qfname)) < 0) {
+ errstr(_("Quota file not found or has wrong format.\n"));
goto out_handle;
}
- if (qfname[0] && (!QIO_ENABLED(h) || flags & IOI_OPENFILE)) { /* Need to open file? */
+ if (!QIO_ENABLED(h) || flags & IOI_OPENFILE) { /* Need to open file? */
/* We still need to open file for operations like 'repquota' */
if ((fd = open(qfname, QIO_RO(h) ? O_RDONLY : O_RDWR)) < 0) {
errstr(_("Can't open quotafile %s: %s\n"),
@@ -136,17 +104,7 @@ struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags)
flock(fd, QIO_RO(h) ? LOCK_SH : LOCK_EX);
/* Init handle */
h->qh_fd = fd;
-
- /* Check file format */
- h->qh_fmt = detect_qf_format(fd, type);
- if (h->qh_fmt == -2) {
- errstr(_("Quotafile format too new in %s\n"), qfname);
- goto out_lock;
- }
- if (fmt != -1 && h->qh_fmt != fmt) {
- errstr(_("Quotafile format detected differs from the specified one (or the one kernel uses on the file).\n"));
- goto out_lock;
- }
+ h->qh_fmt = fmt;
}
else {
h->qh_fd = -1;
@@ -192,7 +150,7 @@ struct quota_handle *new_io(struct mntent *mnt, int type, int fmt)
fmt == QF_RPC ? "RPC" : "XFS");
return NULL;
}
- if (!hasquota(mnt, type) || !(qfname = get_qf_name(mnt, type, fmt)))
+ if (get_qf_name(mnt, type, (1 << fmt), 0, &qfname) < 0)
return NULL;
sstrncpy(namebuf, qfname, PATH_MAX);
sstrncat(namebuf, ".new", PATH_MAX);
diff --git a/quotaio.h b/quotaio.h
index 22c6d8a..74150b9 100644
--- a/quotaio.h
+++ b/quotaio.h
@@ -41,6 +41,7 @@
}
/* Values for format handling */
+#define QF_UNKNOWN -3 /* Format cannot be detected from filename */
#define QF_TOONEW -2 /* Quota format is too new to handle */
#define QF_ERROR -1 /* There was error while detecting format (maybe unknown format...) */
#define QF_VFSOLD 0 /* Old quota format */
@@ -129,12 +130,13 @@ struct dquot {
};
/* Flags for commit function (have effect only when quota in kernel is turned on) */
-#define COMMIT_USAGE 1
-#define COMMIT_LIMITS 2
+#define COMMIT_USAGE QIF_USAGE
+#define COMMIT_LIMITS QIF_LIMITS
#define COMMIT_ALL (COMMIT_USAGE | COMMIT_LIMITS)
/* Structure of quotafile operations */
struct quotafile_ops {
+ int (*check_file) (int fd, int type); /* Check whether quotafile is in our format */
int (*init_io) (struct quota_handle * h); /* Open quotafile */
int (*new_io) (struct quota_handle * h); /* Create new quotafile */
int (*end_io) (struct quota_handle * h); /* Write all changes and close quotafile */
@@ -153,9 +155,6 @@ 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)
-/* Detect format of given quotafile */
-int detect_qf_format(int fd, int type);
-
/* Check quota format used on specified medium and initialize it */
struct quota_handle *init_io(struct mntent *mnt, int type, int fmt, int flags);
diff --git a/quotaio_rpc.c b/quotaio_rpc.c
index 258ccc7..ce9dace 100644
--- a/quotaio_rpc.c
+++ b/quotaio_rpc.c
@@ -17,13 +17,8 @@ static struct dquot *rpc_read_dquot(struct quota_handle *h, qid_t id);
static int rpc_commit_dquot(struct dquot *dquot, int flags);
struct quotafile_ops quotafile_ops_rpc = {
- NULL, /* init_io */
- NULL, /* new_io */
- NULL, /* end_io */
- NULL, /* write_info */
- rpc_read_dquot,
- rpc_commit_dquot,
- NULL /* scan_dquots */
+read_dquot: rpc_read_dquot,
+commit_dquot: rpc_commit_dquot
};
/*
diff --git a/quotaio_v1.c b/quotaio_v1.c
index 195534c..d565e01 100644
--- a/quotaio_v1.c
+++ b/quotaio_v1.c
@@ -34,7 +34,7 @@
#ident "$Copyright: (c) 1980, 1990 Regents of the University of California. $"
#ident "$Copyright: All rights reserved. $"
-#ident "$Id: quotaio_v1.c,v 1.11 2001/11/08 23:56:11 jkar8572 Exp $"
+#ident "$Id: quotaio_v1.c,v 1.12 2002/03/27 16:21:26 jkar8572 Exp $"
#include <unistd.h>
#include <errno.h>
@@ -47,7 +47,9 @@
#include "dqblk_v1.h"
#include "quotaio.h"
#include "quotasys.h"
+#include "quotaio_generic.h"
+static int v1_check_file(int fd, int type);
static int v1_init_io(struct quota_handle *h);
static int v1_new_io(struct quota_handle *h);
static int v1_write_info(struct quota_handle *h);
@@ -56,6 +58,7 @@ static int v1_commit_dquot(struct dquot *dquot, int flags);
static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *dquot, char *dqname));
struct quotafile_ops quotafile_ops_1 = {
+check_file: v1_check_file,
init_io: v1_init_io,
new_io: v1_new_io,
write_info: v1_write_info,
@@ -121,23 +124,43 @@ static inline void v1_util2kerndqblk(struct v1_kern_dqblk *k, struct util_dqblk
}
/*
+ * Check whether quotafile is in our format
+ */
+static int v1_check_file(int fd, int type)
+{
+ struct stat st;
+
+ if (fstat(fd, &st) < 0)
+ return 0;
+ if (!st.st_size || st.st_size % sizeof(struct v1_disk_dqblk))
+ return 0;
+ return 1;
+}
+
+/*
* Open quotafile
*/
static int v1_init_io(struct quota_handle *h)
{
if (QIO_ENABLED(h)) {
- struct v1_kern_dqblk kdqblk;
-
- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) {
- if (errno == EPERM) { /* We have no permission to get this information? */
- h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */
- }
- else
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_get_info(h) < 0)
return -1;
}
else {
- h->qh_info.dqi_bgrace = kdqblk.dqb_btime;
- h->qh_info.dqi_igrace = kdqblk.dqb_itime;
+ struct v1_kern_dqblk kdqblk;
+
+ if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0) {
+ if (errno == EPERM) { /* We have no permission to get this information? */
+ h->qh_info.dqi_bgrace = h->qh_info.dqi_igrace = 0; /* It hopefully won't be needed */
+ }
+ else
+ return -1;
+ }
+ else {
+ h->qh_info.dqi_bgrace = kdqblk.dqb_btime;
+ h->qh_info.dqi_igrace = kdqblk.dqb_itime;
+ }
}
}
else {
@@ -187,14 +210,20 @@ static int v1_write_info(struct quota_handle *h)
return -1;
}
if (QIO_ENABLED(h)) {
- struct v1_kern_dqblk kdqblk;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_set_info(h, IIF_BGRACE | IIF_IGRACE) < 0)
+ return -1;
+ }
+ else {
+ struct v1_kern_dqblk kdqblk;
- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
- return -1;
- kdqblk.dqb_btime = h->qh_info.dqi_bgrace;
- kdqblk.dqb_itime = h->qh_info.dqi_igrace;
- if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
- return -1;
+ if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
+ return -1;
+ kdqblk.dqb_btime = h->qh_info.dqi_bgrace;
+ kdqblk.dqb_itime = h->qh_info.dqi_igrace;
+ if (quotactl(QCMD(Q_V1_SETQUOTA, h->qh_type), h->qh_quotadev, 0, (void *)&kdqblk) < 0)
+ return -1;
+ }
}
else {
struct v1_disk_dqblk ddqblk;
@@ -223,13 +252,21 @@ static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id)
dquot->dq_id = id;
dquot->dq_h = h;
if (QIO_ENABLED(h)) { /* Does kernel use the file? */
- struct v1_kern_dqblk kdqblk;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_get_dquot(dquot) < 0) {
+ free(dquot);
+ return NULL;
+ }
+ }
+ else {
+ struct v1_kern_dqblk kdqblk;
- if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
- free(dquot);
- return NULL;
+ if (quotactl(QCMD(Q_V1_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
+ free(dquot);
+ return NULL;
+ }
+ v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
}
- v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
}
else {
lseek(h->qh_fd, (long)V1_DQOFF(id), SEEK_SET);
@@ -267,19 +304,25 @@ static int v1_commit_dquot(struct dquot *dquot, int flags)
return -1;
}
if (QIO_ENABLED(h)) { /* Kernel uses same file? */
- struct v1_kern_dqblk kdqblk;
- int cmd;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_set_dquot(dquot, flags) < 0)
+ return -1;
+ }
+ else {
+ struct v1_kern_dqblk kdqblk;
+ int cmd;
- if (flags == COMMIT_USAGE)
- cmd = Q_V1_SETUSE;
- else if (flags == COMMIT_LIMITS)
- cmd = Q_V1_SETQLIM;
- else
- cmd = Q_V1_SETQUOTA;
- v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
- if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id,
- (void *)&kdqblk) < 0)
- return -1;
+ if (flags == COMMIT_USAGE)
+ cmd = Q_V1_SETUSE;
+ else if (flags == COMMIT_LIMITS)
+ cmd = Q_V1_SETQLIM;
+ else
+ cmd = Q_V1_SETQUOTA;
+ v1_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
+ if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev, dquot->dq_id,
+ (void *)&kdqblk) < 0)
+ return -1;
+ }
}
else {
v1_mem2diskdqblk(&ddqblk, &dquot->dq_dqb);
@@ -304,7 +347,8 @@ static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct d
qid_t id = 0;
if (QIO_ENABLED(h)) /* Kernel uses same file? */
- if (quotactl(QCMD(Q_SYNC, h->qh_type), h->qh_quotadev, 0, NULL) < 0)
+ if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC, h->qh_type),
+ h->qh_quotadev, 0, NULL) < 0)
die(4, _("Can't sync quotas on device %s: %s\n"), h->qh_quotadev,
strerror(errno));
memset(dquot, 0, sizeof(*dquot));
diff --git a/quotaio_v2.c b/quotaio_v2.c
index 3fe02df..9fc7e43 100644
--- a/quotaio_v2.c
+++ b/quotaio_v2.c
@@ -18,9 +18,11 @@
#include "dqblk_v2.h"
#include "quotaio.h"
#include "quotasys.h"
+#include "quotaio_generic.h"
typedef char *dqbuf_t;
+static int v2_check_file(int fd, int type);
static int v2_init_io(struct quota_handle *h);
static int v2_new_io(struct quota_handle *h);
static int v2_write_info(struct quota_handle *h);
@@ -30,6 +32,7 @@ static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct d
static int v2_report(struct quota_handle *h, int verbose);
struct quotafile_ops quotafile_ops_2 = {
+check_file: v2_check_file,
init_io: v2_init_io,
new_io: v2_new_io,
write_info: v2_write_info,
@@ -42,12 +45,6 @@ report: v2_report
#define getdqbuf() smalloc(V2_DQBLKSIZE)
#define freedqbuf(buf) free(buf)
-static inline void mark_quotafile_metainfo_dirty(struct quota_handle *h)
-{
- h->qh_info.u.v2_mdqi.dqi_flags |= V2_IOFL_METAINFO_DIRTY;
- mark_quotafile_info_dirty(h);
-}
-
/*
* Copy dquot from disk to memory
*/
@@ -139,25 +136,53 @@ static int empty_dquot(struct v2_disk_dqblk *d)
}
/*
+ * Check whether given quota file is in our format
+ */
+static int v2_check_file(int fd, int type)
+{
+ struct v2_disk_dqheader h;
+ int file_magics[] = INITQMAGICS;
+ int known_versions[] = INIT_V2_VERSIONS;
+
+ lseek(fd, 0, SEEK_SET);
+ if (read(fd, &h, sizeof(h)) != sizeof(h))
+ return 0;
+ if (__le32_to_cpu(h.dqh_magic) != file_magics[type]) {
+ if (__be32_to_cpu(h.dqh_magic) == file_magics[type])
+ die(3, _("Your quota file is stored in wrong endianity. Please use convertquota(8) to convert it.\n"));
+ return 0;
+ }
+ if (__le32_to_cpu(h.dqh_version) > known_versions[type])
+ return 0;
+ return 1;
+}
+
+/*
* Open quotafile
*/
static int v2_init_io(struct quota_handle *h)
{
if (QIO_ENABLED(h)) {
- struct v2_kern_dqinfo kdqinfo;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_get_info(h) < 0)
+ return -1;
+ }
+ else {
+ struct v2_kern_dqinfo kdqinfo;
- if (quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) {
- /* Temporary check just before fix gets to kernel */
- if (errno == EPERM) /* Don't have permission to get information? */
- return 0;
- return -1;
+ if (quotactl(QCMD(Q_V2_GETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0) {
+ /* Temporary check just before fix gets to kernel */
+ if (errno == EPERM) /* Don't have permission to get information? */
+ return 0;
+ return -1;
+ }
+ h->qh_info.dqi_bgrace = kdqinfo.dqi_bgrace;
+ h->qh_info.dqi_igrace = kdqinfo.dqi_igrace;
+ h->qh_info.u.v2_mdqi.dqi_flags = kdqinfo.dqi_flags;
+ h->qh_info.u.v2_mdqi.dqi_blocks = kdqinfo.dqi_blocks;
+ h->qh_info.u.v2_mdqi.dqi_free_blk = kdqinfo.dqi_free_blk;
+ h->qh_info.u.v2_mdqi.dqi_free_entry = kdqinfo.dqi_free_entry;
}
- h->qh_info.dqi_bgrace = kdqinfo.dqi_bgrace;
- h->qh_info.dqi_igrace = kdqinfo.dqi_igrace;
- h->qh_info.u.v2_mdqi.dqi_flags = kdqinfo.dqi_flags;
- h->qh_info.u.v2_mdqi.dqi_blocks = kdqinfo.dqi_blocks;
- h->qh_info.u.v2_mdqi.dqi_free_blk = kdqinfo.dqi_free_blk;
- h->qh_info.u.v2_mdqi.dqi_free_entry = kdqinfo.dqi_free_entry;
}
else {
struct v2_disk_dqinfo ddqinfo;
@@ -211,22 +236,22 @@ static int v2_write_info(struct quota_handle *h)
return -1;
}
if (QIO_ENABLED(h)) {
- struct v2_kern_dqinfo kdqinfo;
-
- kdqinfo.dqi_bgrace = h->qh_info.dqi_bgrace;
- kdqinfo.dqi_igrace = h->qh_info.dqi_igrace;
- kdqinfo.dqi_flags = h->qh_info.u.v2_mdqi.dqi_flags;
- kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_blocks;
- kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_free_blk;
- kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_free_entry;
- if (h->qh_info.u.v2_mdqi.dqi_flags & V2_IOFL_METAINFO_DIRTY) {
- if (quotactl(QCMD(Q_V2_SETINFO, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0)
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_set_info(h, IIF_BGRACE | IIF_IGRACE))
return -1;
}
else {
+ struct v2_kern_dqinfo kdqinfo;
+
+ kdqinfo.dqi_bgrace = h->qh_info.dqi_bgrace;
+ kdqinfo.dqi_igrace = h->qh_info.dqi_igrace;
+ kdqinfo.dqi_flags = h->qh_info.u.v2_mdqi.dqi_flags;
+ kdqinfo.dqi_blocks = h->qh_info.u.v2_mdqi.dqi_blocks;
+ kdqinfo.dqi_free_blk = h->qh_info.u.v2_mdqi.dqi_free_blk;
+ kdqinfo.dqi_free_entry = h->qh_info.u.v2_mdqi.dqi_free_entry;
if (quotactl(QCMD(Q_V2_SETGRACE, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0 ||
quotactl(QCMD(Q_V2_SETFLAGS, h->qh_type), h->qh_quotadev, 0, (void *)&kdqinfo) < 0)
- return -1;
+ return -1;
}
}
else {
@@ -289,7 +314,7 @@ static int get_free_dqblk(struct quota_handle *h)
}
blk = info->dqi_blocks++;
}
- mark_quotafile_metainfo_dirty(h);
+ mark_quotafile_info_dirty(h);
freedqbuf(buf);
return blk;
}
@@ -304,7 +329,7 @@ static void put_free_dqblk(struct quota_handle *h, dqbuf_t buf, uint blk)
dh->dqdh_prev_free = __cpu_to_le32(0);
dh->dqdh_entries = __cpu_to_le16(0);
info->dqi_free_blk = blk;
- mark_quotafile_metainfo_dirty(h);
+ mark_quotafile_info_dirty(h);
write_blk(h, blk, buf);
}
@@ -329,7 +354,7 @@ static void remove_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk)
}
else {
h->qh_info.u.v2_mdqi.dqi_free_entry = nextblk;
- mark_quotafile_metainfo_dirty(h);
+ mark_quotafile_info_dirty(h);
}
freedqbuf(tmpbuf);
dh->dqdh_next_free = dh->dqdh_prev_free = __cpu_to_le32(0);
@@ -353,7 +378,7 @@ static void insert_free_dqentry(struct quota_handle *h, dqbuf_t buf, uint blk)
}
freedqbuf(tmpbuf);
info->dqi_free_entry = blk;
- mark_quotafile_metainfo_dirty(h);
+ mark_quotafile_info_dirty(h);
}
/* Find space for dquot */
@@ -382,7 +407,7 @@ static uint find_free_dqentry(struct quota_handle *h, struct dquot *dquot, int *
}
memset(buf, 0, V2_DQBLKSIZE);
info->dqi_free_entry = blk;
- mark_quotafile_metainfo_dirty(h);
+ mark_quotafile_info_dirty(h);
}
if (__le16_to_cpu(dh->dqdh_entries) + 1 >= V2_DQSTRINBLK) /* Block will be full? */
remove_free_dqentry(h, buf, blk);
@@ -608,13 +633,21 @@ static struct dquot *v2_read_dquot(struct quota_handle *h, qid_t id)
memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));
if (QIO_ENABLED(h)) {
- struct v2_kern_dqblk kdqblk;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_get_dquot(dquot) < 0) {
+ free(dquot);
+ return NULL;
+ }
+ }
+ else {
+ struct v2_kern_dqblk kdqblk;
- if (quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
- free(dquot);
- return NULL;
+ if (quotactl(QCMD(Q_V2_GETQUOTA, h->qh_type), h->qh_quotadev, id, (void *)&kdqblk) < 0) {
+ free(dquot);
+ return NULL;
+ }
+ v2_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
}
- v2_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
return dquot;
}
offset = find_dqentry(h, dquot);
@@ -647,19 +680,25 @@ static int v2_commit_dquot(struct dquot *dquot, int flags)
return -1;
}
if (QIO_ENABLED(dquot->dq_h)) {
- struct v2_kern_dqblk kdqblk;
- int cmd;
-
- if (flags == COMMIT_USAGE)
- cmd = Q_V2_SETUSE;
- else if (flags == COMMIT_LIMITS)
- cmd = Q_V2_SETQLIM;
- else
- cmd = Q_V2_SETQUOTA;
- v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
- if (quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev,
- dquot->dq_id, (void *)&kdqblk) < 0)
- return -1;
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_set_dquot(dquot, flags) < 0)
+ return -1;
+ }
+ else {
+ struct v2_kern_dqblk kdqblk;
+ int cmd;
+
+ if (flags == COMMIT_USAGE)
+ cmd = Q_V2_SETUSE;
+ else if (flags == COMMIT_LIMITS)
+ cmd = Q_V2_SETQLIM;
+ else
+ cmd = Q_V2_SETQUOTA;
+ v2_util2kerndqblk(&kdqblk, &dquot->dq_dqb);
+ if (quotactl(QCMD(cmd, dquot->dq_h->qh_type), dquot->dq_h->qh_quotadev,
+ dquot->dq_id, (void *)&kdqblk) < 0)
+ return -1;
+ }
return 0;
}
if (!b->dqb_curspace && !b->dqb_curinodes && !b->dqb_bsoftlimit && !b->dqb_isoftlimit
@@ -739,12 +778,18 @@ static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct d
{
char *bitmap;
struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi;
+ struct v2_disk_dqinfo ddqinfo;
struct dquot *dquot = get_empty_dquot();
if (QIO_ENABLED(h)) /* Kernel uses same file? */
- if (quotactl(QCMD(Q_SYNC, h->qh_type), h->qh_quotadev, 0, NULL) < 0)
+ if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC, h->qh_type),
+ h->qh_quotadev, 0, NULL) < 0)
die(4, _("Can't sync quotas on device %s: %s\n"), h->qh_quotadev,
strerror(errno));
+ lseek(h->qh_fd, V2_DQINFOOFF, SEEK_SET);
+ if (read(h->qh_fd, &ddqinfo, sizeof(ddqinfo)) != sizeof(ddqinfo))
+ return -1;
+ info->dqi_blocks = __le32_to_cpu(ddqinfo.dqi_blocks);
dquot->dq_h = h;
bitmap = smalloc((info->dqi_blocks + 7) >> 3);
memset(bitmap, 0, (info->dqi_blocks + 7) >> 3);
@@ -758,12 +803,12 @@ static int v2_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct d
/* Report information about quotafile */
static int v2_report(struct quota_handle *h, int verbose)
{
- struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi;
+ if (verbose) {
+ struct v2_mem_dqinfo *info = &h->qh_info.u.v2_mdqi;
- if (verbose)
- printf
- ("Statistics:\nTotal blocks: %u\nData blocks: %u\nEntries: %u\nUsed average: %f\n",
+ printf(_("Statistics:\nTotal blocks: %u\nData blocks: %u\nEntries: %u\nUsed average: %f\n"),
info->dqi_blocks, info->dqi_data_blocks, info->dqi_used_entries,
((float)info->dqi_used_entries) / info->dqi_data_blocks);
+ }
return 0;
}
diff --git a/quotaio_v2.h b/quotaio_v2.h
index bb3a000..2482156 100644
--- a/quotaio_v2.h
+++ b/quotaio_v2.h
@@ -20,8 +20,6 @@
#define V2_GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)(buf)) + sizeof(struct v2_disk_dqdbheader)))
#define INIT_V2_VERSIONS { 0, 0}
-#define V2_IOFL_METAINFO_DIRTY 0x100 /* Is dirty also metadata information in info? */
-
struct v2_disk_dqheader {
u_int32_t dqh_magic; /* Magic number identifying file */
u_int32_t dqh_version; /* File version */
diff --git a/quotaon.8 b/quotaon.8
index 26c0aee..99f6401 100644
--- a/quotaon.8
+++ b/quotaon.8
@@ -6,12 +6,18 @@ quotaon, quotaoff \- turn filesystem quotas on and off
.B /usr/sbin/quotaon
[
.B \-vugfp
+] [
+.B \-F
+.I format-name
]
.IR filesystem .\|.\|.
.br
.B /usr/sbin/quotaon
[
.B \-avugfp
+] [
+.B \-F
+.I format-name
]
.LP
.B /usr/sbin/quotaoff
@@ -102,6 +108,16 @@ behave like being called as
.BR quotaoff .
.SS quotaoff
.TP
+.B \-F \f2format-name\f1
+Report quota for specified format (ie. don't perform format autodetection).
+Possible format names are:
+.B vfsold
+(version 1 quota),
+.B vfsv0
+(version 2 quota),
+.B xfs
+(quota on XFS filesystem)
+.TP
.B \-a
Force all filesystems in
.B /etc/fstab
diff --git a/quotaon.c b/quotaon.c
index 7f8d3b8..6aa9899 100644
--- a/quotaon.c
+++ b/quotaon.c
@@ -34,7 +34,7 @@
#ident "$Copyright: (c) 1980, 1990 Regents of the University of California $"
#ident "$Copyright: All rights reserved. $"
-#ident "$Id: quotaon.c,v 1.13 2002/02/27 21:23:55 jkar8572 Exp $"
+#ident "$Id: quotaon.c,v 1.14 2002/03/27 16:21:26 jkar8572 Exp $"
/*
* Turn quota on/off for a filesystem.
@@ -46,114 +46,58 @@
#include <stdlib.h>
#include "quotaon.h"
+#include "quota.h"
+#include "quotasys.h"
-int aflag; /* all file systems */
-int gflag; /* operate on group quotas */
-int uflag; /* operate on user quotas */
-int vflag; /* verbose */
-int pflag; /* just print status */
-int kqf; /* kernel quota format */
+#define FL_USER 1
+#define FL_GROUP 2
+#define FL_VERBOSE 4
+#define FL_ALL 8
+#define FL_STAT 16
+#define FL_OFF 32
+
+int flags, fmt = -1;
char *progname;
+char **mntpoints;
+int mntcnt;
+char *xarg = NULL;
static void usage(void)
{
- errstr(_("Usage:\n\t%s [-guvp] [-x state] -a\n\t%s [-guvp] [-x state] filesys ...\n"), progname, progname);
+ errstr(_("Usage:\n\t%s [-guvp] [-F quotaformat] [-x state] -a\n\t%s [-guvp] [-F quotaformat] [-x state] filesys ...\n"), progname, progname);
exit(1);
}
-/*
- * 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 offmode, int type, char *extra)
-{
- int flags, ret = 0;
- newstate_t *statefunc;
-
- flags = offmode ? STATEFLAG_OFF : STATEFLAG_ON;
- if (vflag > 1)
- flags |= STATEFLAG_VERYVERBOSE;
- else if (vflag)
- flags |= STATEFLAG_VERBOSE;
- if (aflag)
- flags |= STATEFLAG_ALL;
-
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */
- if (!(kqf & (1 << QF_XFS))) {
- errstr("Can't change state of XFS quota. It's not compiled in kernel.\n");
- return 1;
- }
- if (kqf & (1 << QF_XFS) &&
- ((offmode && (kern_quota_on(mnt->mnt_fsname, USRQUOTA, 1 << QF_XFS)
- || kern_quota_on(mnt->mnt_fsname, GRPQUOTA, 1 << QF_XFS)))
- || (!offmode && kern_quota_on(mnt->mnt_fsname, type, 1 << QF_XFS))))
- ret = xfs_newstate(mnt, type, extra, flags);
- }
- else {
- extra = get_qf_name(mnt, type, (kqf & (1 << QF_VFSV0)) ? QF_VFSV0 : QF_VFSOLD);
- statefunc = (kqf & (1 << QF_VFSV0)) ? v2_newstate : v1_newstate;
- ret = statefunc(mnt, type, extra, flags);
- free(extra);
- }
- return ret;
-}
-
-/* Print state of quota (on/off) */
-static int print_state(struct mntent *mnt, int type)
-{
- int on = 0;
-
- if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) {
- if (kqf & (1 << QF_XFS))
- on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_XFS) != -1;
- }
- else if (kqf & (1 << QF_VFSV0))
- on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_VFSV0) != -1;
- else if (kqf & (1 << QF_VFSOLD))
- on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_VFSOLD) != -1;
-
- printf("%s quota on %s (%s) is %s\n", type2name(type), mnt->mnt_dir, mnt->mnt_fsname,
- on ? "on" : "off");
-
- return on;
-}
-
-int main(int argc, char **argv)
+static void parse_options(int argcnt, char **argstr)
{
- struct mntent *mnt;
- char *xarg = NULL;
- int c, offmode = 0, errs = 0;
+ int c;
- gettexton();
-
- progname = basename(argv[0]);
- if (strcmp(progname, "quotaoff") == 0)
- offmode++;
- else if (strcmp(progname, "quotaon") != 0)
- die(1, _("Name must be quotaon or quotaoff not %s\n"), progname);
-
- while ((c = getopt(argc, argv, "afvugpx:V")) != -1) {
+ while ((c = getopt(argcnt, argstr, "afvugpx:VF:")) != -1) {
switch (c) {
case 'a':
- aflag++;
+ flags |= FL_ALL;
break;
case 'f':
- offmode++;
+ flags |= FL_OFF;
break;
case 'g':
- gflag++;
+ flags |= FL_GROUP;
break;
case 'u':
- uflag++;
+ flags |= FL_USER;
break;
case 'v':
- vflag++;
+ flags |= FL_VERBOSE;
break;
case 'x':
xarg = optarg;
break;
case 'p':
- pflag++;
+ flags |= FL_STAT;
+ break;
+ case 'F':
+ if ((fmt = name2fmt(optarg)) == QF_ERROR)
+ exit(1);
break;
case 'V':
version();
@@ -162,58 +106,95 @@ int main(int argc, char **argv)
usage();
}
}
- argc -= optind;
- argv += optind;
-
- if (argc <= 0 && !aflag)
+ if ((flags & FL_ALL && optind != argcnt) || (!(flags & FL_ALL) && optind == argcnt)) {
+ fputs(_("Bad number of arguments.\n"), stderr);
usage();
- if (!gflag && !uflag) {
- gflag++;
- uflag++;
}
-
- kqf = kern_quota_format();
- if (kqf == QF_TOONEW) {
- errstr(_("WARNING - Kernel quota newer than supported! Quota need not work properly.\n"));
- kqf = 1 << QF_VFSV0;
+ if (fmt == QF_RPC) {
+ fputs(_("Can't turn on/off quotas via RPC.\n"), stderr);
+ exit(1);
}
+ if (!(flags & (FL_USER | FL_GROUP)))
+ flags |= FL_USER | FL_GROUP;
+ if (!(flags & FL_ALL)) {
+ mntpoints = argstr + optind;
+ mntcnt = argcnt - optind;
+ }
+}
- if (init_mounts_scan(aflag ? 0 : argc, argv) < 0)
- return 1;
- while ((mnt = get_next_mount(0))) {
- if (!strcmp(mnt->mnt_type, MNTTYPE_NFS)) {
- if (!aflag)
- fprintf(stderr, "%s: Quota can't be turned on on NFS filesystem\n", mnt->mnt_fsname);
- continue;
- }
+/*
+ * 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)
+{
+ int sflags, ret = 0, usefmt;
+ newstate_t *statefunc;
+
+ sflags = flags & FL_OFF ? STATEFLAG_OFF : STATEFLAG_ON;
+ if (flags & FL_VERBOSE)
+ sflags |= STATEFLAG_VERBOSE;
+ if (flags & FL_ALL)
+ sflags |= STATEFLAG_ALL;
- if (!pflag) {
- if (gflag)
- errs += newstate(mnt, offmode, GRPQUOTA, xarg);
- if (uflag)
- errs += newstate(mnt, offmode, USRQUOTA, xarg);
+ if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) { /* XFS filesystem has special handling... */
+ if (!(kernel_formats & (1 << QF_XFS))) {
+ errstr(_("Can't change state of XFS quota. It's not compiled in kernel.\n"));
+ return 1;
}
- else {
- if (gflag)
- errs += print_state(mnt, GRPQUOTA);
- if (uflag)
- errs += print_state(mnt, USRQUOTA);
+ if (kernel_formats & (1 << QF_XFS) &&
+ ((flags & FL_OFF && (kern_quota_on(mnt->mnt_fsname, USRQUOTA, 1 << QF_XFS)
+ || kern_quota_on(mnt->mnt_fsname, GRPQUOTA, 1 << QF_XFS)))
+ || (!(flags & FL_OFF) && kern_quota_on(mnt->mnt_fsname, type, 1 << QF_XFS))))
+ ret = xfs_newstate(mnt, type, extra, sflags);
+ }
+ else {
+ if (!hasquota(mnt, type))
+ return 0;
+ usefmt = get_qf_name(mnt, type, fmt == -1 ? kernel_formats : (1 << fmt), NF_FORMAT, &extra);
+ if (usefmt < 0) {
+ errstr(_("Cannot find quota file on %s [%s] to turn quotas on/off.\n"), mnt->mnt_dir, mnt->mnt_fsname);
+ return 1;
}
+ statefunc = (usefmt == QF_VFSV0) ? v2_newstate : v1_newstate;
+ ret = statefunc(mnt, type, extra, sflags);
+ free(extra);
}
- end_mounts_scan();
+ return ret;
+}
- return errs;
+/* Print state of quota (on/off) */
+static int print_state(struct mntent *mnt, int type)
+{
+ int on = 0;
+
+ if (!strcmp(mnt->mnt_type, MNTTYPE_XFS)) {
+ if (kernel_formats & (1 << QF_XFS))
+ on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_XFS) != -1;
+ }
+ else if (kernel_formats & (1 << QF_VFSV0))
+ on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_VFSV0) != -1;
+ else if (kernel_formats & (1 << QF_VFSOLD))
+ on = kern_quota_on(mnt->mnt_fsname, type, 1 << QF_VFSOLD) != -1;
+
+ printf("%s quota on %s (%s) is %s\n", type2name(type), mnt->mnt_dir, mnt->mnt_fsname,
+ on ? "on" : "off");
+
+ return on;
}
/*
* Enable/disable VFS quota on given filesystem
*/
-static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, int flags)
+static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type, int fmt, int flags)
{
- int qcmd;
+ int qcmd, kqf;
if (flags & STATEFLAG_OFF) {
- qcmd = QCMD(Q_QUOTAOFF, type);
+ if (kernel_iface == IFACE_GENERIC)
+ qcmd = QCMD(Q_QUOTAOFF, type);
+ else
+ qcmd = QCMD(Q_6_5_QUOTAOFF, type);
if (quotactl(qcmd, quotadev, 0, NULL) < 0) {
errstr(_("quotactl on %s [%s]: %s\n"), quotadev, quotadir, strerror(errno));
return 1;
@@ -222,8 +203,15 @@ static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type,
printf(_("%s [%s]: %s quotas turned off\n"), quotadev, quotadir, type2name(type));
return 0;
}
- qcmd = QCMD(Q_QUOTAON, type);
- if (quotactl(qcmd, quotadev, 0, (void *)quotafile) < 0) {
+ if (kernel_iface == IFACE_GENERIC) {
+ qcmd = QCMD(Q_QUOTAON, type);
+ kqf = util2kernfmt(fmt);
+ }
+ else {
+ qcmd = QCMD(Q_6_5_QUOTAON, type);
+ kqf = 0;
+ }
+ if (quotactl(qcmd, quotadev, kqf, (void *)quotafile) < 0) {
if (errno == ENOENT)
errstr(_("can't find %s on %s [%s]\n"), quotafile, quotadev, quotadir);
else
@@ -243,10 +231,23 @@ static int quotaonoff(char *quotadev, char *quotadir, char *quotafile, int type,
static int quotarsquashonoff(const char *quotadev, int type, int flags)
{
#if defined(MNTOPT_RSQUASH)
- int mode = (flags & STATEFLAG_OFF) ? 0 : 1;
- int qcmd = QCMD(Q_V1_RSQUASH, type);
+ int ret;
+
+ if (kernel_iface == IFACE_GENERIC) {
+ int qcmd = QCMD(Q_SETINFO, type);
+ struct if_dqinfo info;
- if (quotactl(qcmd, quotadev, 0, (void *)&mode) < 0) {
+ info.dqi_flags = V1_DQF_RSQUASH;
+ info.dqi_valid = IIF_FLAGS;
+ ret = quotactl(qcmd, quotadev, 0, (void *)&info);
+ }
+ else {
+ int mode = (flags & STATEFLAG_OFF) ? 0 : 1;
+ int qcmd = QCMD(Q_V1_RSQUASH, type);
+
+ ret = quotactl(qcmd, quotadev, 0, (void *)&mode);
+ }
+ if (ret < 0) {
errstr(_("set root_squash on %s: %s\n"), quotadev, strerror(errno));
return 1;
}
@@ -271,7 +272,7 @@ int v1_newstate(struct mntent *mnt, int type, char *file, int flags)
if ((flags & STATEFLAG_OFF) && hasmntopt(mnt, MNTOPT_RSQUASH))
errs += quotarsquashonoff(dev, type, flags);
if (hasquota(mnt, type))
- errs += quotaonoff((char *)dev, mnt->mnt_dir, file, 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);
@@ -289,7 +290,54 @@ int v2_newstate(struct mntent *mnt, int type, char *file, int flags)
if (!dev)
return 1;
if (hasquota(mnt, type))
- errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, flags);
+ errs = quotaonoff((char *)dev, mnt->mnt_dir, file, type, QF_VFSV0, flags);
free((char *)dev);
return errs;
}
+
+int main(int argc, char **argv)
+{
+ struct mntent *mnt;
+ int errs = 0;
+
+ gettexton();
+
+ progname = basename(argv[0]);
+ if (strcmp(progname, "quotaoff") == 0)
+ flags |= FL_OFF;
+ else if (strcmp(progname, "quotaon") != 0)
+ die(1, _("Name must be quotaon or quotaoff not %s\n"), progname);
+
+ parse_options(argc, argv);
+
+ init_kernel_interface();
+ if (fmt != -1 && !(kernel_formats & (1 << fmt)))
+ die(1, _("Required format %s not supported by kernel.\n"), fmt2name(fmt));
+
+ if (init_mounts_scan(mntcnt, mntpoints) < 0)
+ return 1;
+ while ((mnt = get_next_mount(0))) {
+ if (!strcmp(mnt->mnt_type, MNTTYPE_NFS)) {
+ if (!(flags & FL_ALL))
+ fprintf(stderr, "%s: Quota can't be turned on on NFS filesystem\n", mnt->mnt_fsname);
+ continue;
+ }
+
+ if (!(flags & FL_STAT)) {
+ if (flags & FL_GROUP)
+ errs += newstate(mnt, GRPQUOTA, xarg);
+ if (flags & FL_USER)
+ errs += newstate(mnt, USRQUOTA, xarg);
+ }
+ else {
+ if (flags & FL_GROUP)
+ errs += print_state(mnt, GRPQUOTA);
+ if (flags & FL_USER)
+ errs += print_state(mnt, USRQUOTA);
+ }
+ }
+ end_mounts_scan();
+
+ return errs;
+}
+
diff --git a/quotaon.h b/quotaon.h
index ced9b2a..b4be0de 100644
--- a/quotaon.h
+++ b/quotaon.h
@@ -14,7 +14,6 @@
#define STATEFLAG_OFF 0x02
#define STATEFLAG_ALL 0x04
#define STATEFLAG_VERBOSE 0x08
-#define STATEFLAG_VERYVERBOSE 0x10
typedef int (newstate_t) (struct mntent * mnt, int type, char *file, int flags);
extern int v1_newstate(struct mntent *mnt, int type, char *file, int flags);
diff --git a/quotastats.c b/quotastats.c
index 8130989..b3f0d02 100644
--- a/quotastats.c
+++ b/quotastats.c
@@ -10,7 +10,7 @@
*
* Author: Marco van Wieringen <mvw@planets.elm.net>
*
- * Version: $Id: quotastats.c,v 1.8 2001/11/09 08:07:18 jkar8572 Exp $
+ * Version: $Id: quotastats.c,v 1.9 2002/03/27 16:21:26 jkar8572 Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -41,12 +41,13 @@ static inline int get_stats(struct util_dqstats *dqstats)
{
struct v1_dqstats old_dqstats;
struct v2_dqstats v0_dqstats;
+ char tmp[1024];
FILE *f;
int ret = -1;
signal(SIGSEGV, SIG_IGN); /* Ignore SIGSEGV due to bad quotactl() */
if ((f = fopen(QSTAT_FILE, "r"))) {
- if (fscanf(f, "Version %u", &dqstats->version) != 1) {
+ if (fscanf(f, "Version %u\n", &dqstats->version) != 1) {
errstr(_("Can't parse quota version.\n"));
goto out;
}
@@ -54,6 +55,8 @@ static inline int get_stats(struct util_dqstats *dqstats)
errstr(_("Kernel quota version %u is too new.\n"), dqstats->version);
goto out;
}
+ if (dqstats->version >= 6*10000+5*100+1)
+ fgets(tmp, sizeof(tmp), f); /* Skip formats information */
if (fscanf(f, "%u %u %u %u %u %u %u %u", &dqstats->lookups, &dqstats->drops,
&dqstats->reads, &dqstats->writes, &dqstats->cache_hits,
&dqstats->allocated_dquots, &dqstats->free_dquots, &dqstats->syncs) != 8) {
diff --git a/quotasys.c b/quotasys.c
index 04288a7..8b1feec 100644
--- a/quotasys.c
+++ b/quotasys.c
@@ -14,6 +14,7 @@
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
+#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/vfs.h>
@@ -173,6 +174,34 @@ char *fmt2name(int fmt)
}
/*
+ * Convert kernel to utility quota format number
+ */
+int kern2utilfmt(int fmt)
+{
+ switch (fmt) {
+ case QFMT_VFS_OLD:
+ return QF_VFSOLD;
+ case QFMT_VFS_V0:
+ return QF_VFSV0;
+ }
+ return -1;
+}
+
+/*
+ * Convert utility to kernel quota format number
+ */
+int util2kernfmt(int fmt)
+{
+ switch (fmt) {
+ case QF_VFSOLD:
+ return QFMT_VFS_OLD;
+ case QF_VFSV0:
+ return QFMT_VFS_V0;
+ }
+ return -1;
+}
+
+/*
* Convert time difference of seconds and current time
*/
void difftime2str(time_t seconds, char *buf)
@@ -317,71 +346,83 @@ int hasquota(struct mntent *mnt, int type)
}
/* Check whether quotafile for given format exists - return its name in namebuf */
-static int check_fmtfile_exists(struct mntent *mnt, int type, int fmt, char *namebuf)
+static int check_fmtfile_ok(char *name, int type, int fmt, int flags)
{
- struct stat buf;
+ if (!flags)
+ return 1;
+ if (flags & NF_EXIST) {
+ struct stat st;
- snprintf(namebuf, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[fmt], extensions[type]);
- if (!stat(namebuf, &buf))
+ if (stat(name, &st) < 0) {
+ if (errno != ENOENT)
+ errstr(_("Can't stat quota file %s: %s\n"), name, strerror(errno));
+ return 0;
+ }
return 1;
- if (errno != ENOENT) {
- errstr(_("Can't stat quotafile %s: %s\n"),
- namebuf, strerror(errno));
- return -1;
}
- return 0;
+ else {
+ int fd, ret = 0;
+
+ if ((fd = open(name, O_RDONLY)) >= 0) {
+ if (fmt == QF_VFSV0)
+ ret = quotafile_ops_2.check_file(fd, type);
+ else
+ ret = quotafile_ops_1.check_file(fd, type);
+ close(fd);
+ }
+ else if (errno != ENOENT)
+ errstr(_("Can't open quotafile %s: %s\n"), name, strerror(errno));
+ return ret;
+ }
}
/*
- * Get quotafile name for given entry; "" means format has no quota
+ * Get quotafile name for given entry. Return format and quota file name.
* Note that formats without quotafile *must* be detected prior to calling this function
*/
-char *get_qf_name(struct mntent *mnt, int type, int fmt)
+int get_qf_name(struct mntent *mnt, int type, int fmt, int flags, char **filename)
{
char *option, *pathname, has_quota_file_definition = 0;
char qfullname[PATH_MAX] = "";
- if ((type == USRQUOTA) && (option = hasmntopt(mnt, MNTOPT_USRQUOTA))) {
+ if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_USRQUOTA))) {
if (*(pathname = option + strlen(MNTOPT_USRQUOTA)) == '=')
has_quota_file_definition = 1;
}
- else if ((type == GRPQUOTA) && (option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) {
+ else if (type == GRPQUOTA && (option = hasmntopt(mnt, MNTOPT_GRPQUOTA))) {
if (*(pathname = option + strlen(MNTOPT_GRPQUOTA)) == '=')
has_quota_file_definition = 1;
}
- else if ((type == USRQUOTA) && (option = hasmntopt(mnt, MNTOPT_QUOTA))) {
+ else if (type == USRQUOTA && (option = hasmntopt(mnt, MNTOPT_QUOTA))) {
if (*(pathname = option + strlen(MNTOPT_QUOTA)) == '=')
has_quota_file_definition = 1;
}
else
- return NULL;
+ return -1;
if (has_quota_file_definition) {
if ((option = strchr(++pathname, ',')))
- strncpy(qfullname, pathname, min((option - pathname), sizeof(qfullname)));
+ sstrncpy(qfullname, pathname, min((option - pathname), sizeof(qfullname)));
else
- strncpy(qfullname, pathname, sizeof(qfullname));
+ sstrncpy(qfullname, pathname, sizeof(qfullname));
}
- else if (fmt == -1) { /* Should guess quota format? */
- int ret;
-
- if ((ret = check_fmtfile_exists(mnt, type, QF_VFSV0, qfullname)) == -1)
- return NULL;
- if (ret)
- fmt = QF_VFSV0;
- else {
- if ((ret = check_fmtfile_exists(mnt, type, QF_VFSOLD, qfullname)) == -1)
- return NULL;
- if (ret)
- fmt = QF_VFSOLD;
+ if (fmt & (1 << QF_VFSV0)) {
+ if (!has_quota_file_definition)
+ snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSV0], extensions[type]);
+ if (check_fmtfile_ok(qfullname, type, QF_VFSV0, flags)) {
+ *filename = sstrdup(qfullname);
+ return QF_VFSV0;
}
- if (fmt == -1)
- return NULL;
}
- else if (basenames[fmt][0]) /* Any name specified? */
- snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[fmt], extensions[type]);
-
- return sstrdup(qfullname);
+ if (fmt & (1 << QF_VFSOLD)) {
+ if (!has_quota_file_definition)
+ snprintf(qfullname, PATH_MAX, "%s/%s.%s", mnt->mnt_dir, basenames[QF_VFSOLD], extensions[type]);
+ if (check_fmtfile_ok(qfullname, type, QF_VFSOLD, flags)) {
+ *filename = sstrdup(qfullname);
+ return QF_VFSOLD;
+ }
+ }
+ return -1;
}
/*
@@ -468,30 +509,49 @@ int devcmp_handles(struct quota_handle *a, struct quota_handle *b)
* Check kernel quota version
*/
-int kern_quota_format(void)
+int kernel_formats, kernel_iface; /* Formats supported by kernel */
+
+void init_kernel_interface(void)
{
- struct util_dqstats stats;
- struct v2_dqstats v2_stats;
FILE *f;
- int ret = 0;
+ char buf[1024], *c;
+ int actfmt, version = -1;
struct stat st;
- if (!stat("/proc/fs/xfs/stat", &st))
- ret |= (1 << QF_XFS);
+ kernel_formats = 0;
if ((f = fopen(QSTAT_FILE, "r"))) {
- if (fscanf(f, "Version %u", &stats.version) != 1) {
- fclose(f);
- return QF_TOONEW;
+ /* Parse statistics file */
+ fgets(buf, sizeof(buf), f);
+ sscanf(buf, "Version %u", &version);
+ if (version >= 6*10000+5*100+1) {
+ fgets(buf, sizeof(buf), f);
+ c = buf;
+ while ((c = strchr(c, ' '))) {
+ c++;
+ actfmt = kern2utilfmt(strtol(c, NULL, 10));
+ if (actfmt >= 0) /* Known format? */
+ kernel_formats |= 1 << actfmt;
+ }
+ kernel_iface = IFACE_GENERIC;
+ }
+ else {
+ kernel_formats = 1 << QF_VFSV0;
+ kernel_iface = IFACE_VFSV0;
}
fclose(f);
}
- else if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) {
- stats.version = v2_stats.version; /* Copy the version */
- }
else {
- if (errno == ENOSYS || errno == ENOTSUP) /* Quota not compiled? */
- return QF_ERROR;
- if (errno == EINVAL || errno == EFAULT || errno == EPERM) { /* Old quota compiled? */
+ struct v2_dqstats v2_stats;
+
+ if (!stat("/proc/fs/xfs/stat", &st))
+ kernel_formats |= (1 << QF_XFS);
+ if (quotactl(QCMD(Q_V2_GETSTATS, 0), NULL, 0, (void *)&v2_stats) >= 0) {
+ version = v2_stats.version;
+ kernel_formats |= (1 << QF_VFSV0);
+ kernel_iface = IFACE_VFSV0;
+ version = 6*10000+5*100+0;
+ }
+ else if (errno != ENOSYS && errno != ENOTSUP) {
/* RedHat 7.1 (2.4.2-2) newquota check
* Q_V2_GETSTATS in it's old place, Q_GETQUOTA in the new place
* (they haven't moved Q_GETSTATS to its new value) */
@@ -507,31 +567,21 @@ int kern_quota_format(void)
/* On a RedHat 2.4.2-2 we expect 0, EINVAL
* On a 2.4.x we expect 0, ENOENT
* On a 2.4.x-ac we wont get here */
- if (err_stat == 0 && err_quota == EINVAL)
- return ret | (1 << QF_VFSV0); /* New format supported */
- else
- return ret | (1 << QF_VFSOLD);
+ if (err_stat == 0 && err_quota == EINVAL) {
+ kernel_formats |= (1 << QF_VFSV0);
+ kernel_iface = IFACE_VFSV0;
+ version = 6*10000+5*100+0;
+ }
+ else {
+ kernel_formats |= (1 << QF_VFSOLD);
+ kernel_iface = IFACE_VFSOLD;
+ version = 6*10000+4*100+0;
+ }
}
- die(4, _("Error while detecting kernel quota version: %s\n"), strerror(errno));
}
- /* We might do some more generic checks in future but this should be enough for now */
- if (stats.version > KERN_KNOWN_QUOTA_VERSION) /* Newer kernel than we know? */
- return QF_TOONEW;
- if (stats.version <= 6*10000+4*100+0) /* Old quota format? */
- ret |= (1 << QF_VFSOLD);
- else
- ret |= (1 << QF_VFSV0);
- return ret; /* New format supported */
-}
-/*
- * Warn about too new kernel
- */
-void warn_new_kernel(int fmt)
-{
- if (fmt == -1 && kern_quota_format() == QF_TOONEW)
- errstr(
- _("WARNING - Kernel quota is newer than supported. Quotafile used by utils need not be the one used by kernel.\n"));
+ if (version > KERN_KNOWN_QUOTA_VERSION)
+ errstr(_("WARNING - Kernel quota is newer than supported. Quota utilities need not work properly.\n"));
}
/* Check whether old quota is turned on on given device */
@@ -576,6 +626,16 @@ static int xfs_kern_quota_on(const char *dev, int type)
int kern_quota_on(const char *dev, int type, int fmt)
{
/* Check whether quota is turned on... */
+ if (kernel_iface == IFACE_GENERIC) {
+ int actfmt;
+
+ if (quotactl(QCMD(Q_GETFMT, type), dev, 0, (void *)&actfmt) < 0)
+ return -1;
+ actfmt = kern2utilfmt(actfmt);
+ if (actfmt >= 0 && (fmt == -1 || (1 << actfmt) & fmt))
+ return actfmt;
+ return -1;
+ }
if ((fmt & (1 << QF_VFSV0)) && v2_kern_quota_on(dev, type)) /* New quota format */
return QF_VFSV0;
if ((fmt & (1 << QF_XFS)) && xfs_kern_quota_on(dev, type)) /* XFS quota format */
@@ -621,7 +681,7 @@ static int cache_mnt_table(void)
struct mntent *mnt;
struct stat st;
struct statfs fsstat;
- int allocated = 0, i = 0, flags;
+ int allocated = 0, i = 0;
dev_t dev = 0;
char mntpointbuf[PATH_MAX];
@@ -663,8 +723,7 @@ static int cache_mnt_table(void)
free((char *)devname);
continue;
}
-
- flags = 0;
+
if (strcmp(mnt->mnt_type, MNTTYPE_NFS)) {
if (stat(devname, &st) < 0) { /* Can't stat mounted device? */
errstr(_("Can't stat() mounted device %s: %s\n"), devname, strerror(errno));
diff --git a/quotasys.h b/quotasys.h
index 95d0555..db85490 100644
--- a/quotasys.h
+++ b/quotasys.h
@@ -25,7 +25,15 @@
#define IOI_OPENFILE 0x4 /* Open file even if kernel has quotas turned on */
#define QSTAT_FILE "/proc/fs/quota" /* File with quotastats */
-#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 0)
+#define KERN_KNOWN_QUOTA_VERSION (6*10000 + 5*100 + 1)
+
+/* Interface versions */
+#define IFACE_VFSOLD 1
+#define IFACE_VFSV0 2
+#define IFACE_GENERIC 3
+
+/* Kernel quota format and supported interface */
+extern int kernel_formats, kernel_iface;
/*
* Exported functions
@@ -57,6 +65,12 @@ int name2fmt(char *str);
/* Convert quota format number to name */
char *fmt2name(int fmt);
+/* Convert kernel to utility format numbers */
+int kern2utilfmt(int fmt);
+
+/* Convert utility to kernel format numbers */
+int util2kernfmt(int fmt);
+
/* Convert time difference between given time and current time to printable form */
void difftime2str(time_t, char *);
@@ -72,8 +86,14 @@ void number2str(unsigned long long, char *, int);
/* Check to see if particular quota is to be enabled */
int hasquota(struct mntent *mnt, int type);
+/* 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 */
-char *get_qf_name(struct mntent *mnt, int type, int fmt);
+int get_qf_name(struct mntent *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);
/* 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,
@@ -87,11 +107,8 @@ int devcmp_handle(const char *dev, struct quota_handle *h);
/* Check whether two quota handles have same device */
int devcmp_handles(struct quota_handle *a, struct quota_handle *b);
-/* Warn about too new kernel */
-void warn_new_kernel(int fmt);
-
/* Check kernel supported quotafile format */
-int kern_quota_format(void);
+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);
diff --git a/repquota.c b/repquota.c
index 9157f50..a9f440b 100644
--- a/repquota.c
+++ b/repquota.c
@@ -49,12 +49,6 @@ static void usage(void)
static void parse_options(int argcnt, char **argstr)
{
int ret;
- char *slash = strrchr(argstr[0], '/');
-
- if (!slash)
- slash = argstr[0];
- else
- slash++;
while ((ret = getopt(argcnt, argstr, "VavughtsnF:")) != -1) {
switch (ret) {
@@ -256,7 +250,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
parse_options(argc, argv);
- warn_new_kernel(fmt);
+ init_kernel_interface();
if (flags & FL_USER)
report(USRQUOTA);
diff --git a/rquota_svc.c b/rquota_svc.c
index 59a2ed0..c78dc05 100644
--- a/rquota_svc.c
+++ b/rquota_svc.c
@@ -12,7 +12,7 @@
* changes for new utilities by Jan Kara <jack@suse.cz>
* patches by Jani Jaakkola <jjaakkol@cs.helsinki.fi>
*
- * Version: $Id: rquota_svc.c,v 1.9 2001/09/26 12:26:11 jkar8572 Exp $
+ * Version: $Id: rquota_svc.c,v 1.10 2002/03/27 16:21:26 jkar8572 Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -344,8 +344,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
parse_options(argc, argv);
- warn_new_kernel(-1);
-
+ init_kernel_interface();
(void)pmap_unset(RQUOTAPROG, RQUOTAVERS);
(void)pmap_unset(RQUOTAPROG, EXT_RQUOTAVERS);
diff --git a/setquota.c b/setquota.c
index a570bb9..b4171ac 100644
--- a/setquota.c
+++ b/setquota.c
@@ -218,7 +218,7 @@ int main(int argc, char **argv)
progname = basename(argv[0]);
parse_options(argc, argv);
- warn_new_kernel(fmt);
+ init_kernel_interface();
if (flags & FL_ALL)
handles = create_handle_list(0, NULL, flag2type(flags), fmt, (flags & FL_RPC) ? 0 : IOI_LOCALONLY);
diff --git a/warnquota.8 b/warnquota.8
index f89a0ea..e8548a4 100644
--- a/warnquota.8
+++ b/warnquota.8
@@ -73,4 +73,4 @@ default set of users
.SH AUTHORS
.BR warnquota (8)
was written by Marco van Wieringen <mvw@planets.elm.net>, modifications by Jan Kara <jack@suse.cz>.
-This reference page written by Heiko Schlittermann <heiko@lotte.sax.de>, modifications by Jan Kara <jack@suse.cz>
+This reference page written by Heiko Schlittermann <heiko@lotte.sax.de>, modifications by Jan Kara
diff --git a/warnquota.c b/warnquota.c
index 530889d..17638a5 100644
--- a/warnquota.c
+++ b/warnquota.c
@@ -10,7 +10,7 @@
*
* Author: Marco van Wieringen <mvw@planets.elm.net>
*
- * Version: $Id: warnquota.c,v 1.9 2002/02/25 11:26:16 jkar8572 Exp $
+ * Version: $Id: warnquota.c,v 1.10 2002/03/27 16:21:26 jkar8572 Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -463,11 +463,11 @@ static void usage(void)
{
errstr(_("Usage:\n warnquota [-F quotaformat] [-c configfile] [-q quotatabfile]\n"));
}
-
+
static void parse_options(int argcnt, char **argstr)
{
int ret;
-
+
while ((ret = getopt(argcnt, argstr, "VF:hc:q:")) != -1) {
switch (ret) {
case '?':
@@ -489,14 +489,14 @@ static void parse_options(int argcnt, char **argstr)
}
}
}
-
+
int main(int argc, char **argv)
{
gettexton();
progname = basename(argv[0]);
- warn_new_kernel(-1);
parse_options(argc, argv);
+ init_kernel_interface();
warn_quota();
return 0;