From 5975341695e27f23f5a58758954d1ea31c2d0d25 Mon Sep 17 00:00:00 2001 From: jkar8572 Date: Wed, 27 Mar 2002 16:21:26 +0000 Subject: Fixed bug in quota(1) return code. Rewritten detection of kernel version. Added support for generic interface for both quota formats in kernel. --- Changelog | 5 + Makefile.in | 6 +- convertquota.c | 15 ++- edquota.c | 5 +- quota.c | 16 +-- quota.h | 66 ++++++++++++- quotacheck.c | 40 +++++--- quotaio.c | 64 +++--------- quotaio.h | 9 +- quotaio_rpc.c | 9 +- quotaio_v1.c | 114 +++++++++++++++------- quotaio_v2.c | 159 +++++++++++++++++++----------- quotaio_v2.h | 2 - quotaon.8 | 16 +++ quotaon.c | 300 +++++++++++++++++++++++++++++++++------------------------ quotaon.h | 1 - quotastats.c | 7 +- quotasys.c | 209 +++++++++++++++++++++++++--------------- quotasys.h | 29 ++++-- repquota.c | 8 +- rquota_svc.c | 5 +- setquota.c | 2 +- warnquota.8 | 2 +- warnquota.c | 10 +- 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 @@ -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 - 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 #include @@ -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,37 +26,12 @@ #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; u_int32_t dqh_version; } __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 */ @@ -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 #include @@ -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, @@ -120,24 +123,44 @@ static inline void v1_util2kerndqblk(struct v1_kern_dqblk *k, struct util_dqblk k->dqb_btime = u->dqb_btime; } +/* + * 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 */ @@ -138,26 +135,54 @@ static int empty_dquot(struct v2_disk_dqblk *d) return !memcmp(d, &fakedquot, sizeof(fakedquot)); } +/* + * 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 #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 * - * 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 #include #include +#include #include #include #include @@ -172,6 +173,34 @@ char *fmt2name(int fmt) return fmtnames[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 */ @@ -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 * patches by Jani Jaakkola * - * 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 , modifications by Jan Kara . -This reference page written by Heiko Schlittermann , modifications by Jan Kara +This reference page written by Heiko Schlittermann , 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 * - * 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; -- cgit v1.2.3