summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lib/libc/sys/quotactl.222
-rw-r--r--lib/libutil/quotafile.c34
-rw-r--r--sys/ufs/ufs/quota.h2
-rw-r--r--sys/ufs/ufs/ufs_quota.c39
-rw-r--r--sys/ufs/ufs/ufs_vfsops.c4
-rw-r--r--usr.bin/quota/Makefile1
-rw-r--r--usr.sbin/repquota/repquota.c2
7 files changed, 80 insertions, 24 deletions
diff --git a/lib/libc/sys/quotactl.2 b/lib/libc/sys/quotactl.2
index 4b4dca5..ff3cb4b 100644
--- a/lib/libc/sys/quotactl.2
+++ b/lib/libc/sys/quotactl.2
@@ -84,7 +84,7 @@ and group identifiers (GRPQUOTA).
The
.Dq ufs
specific commands are:
-.Bl -tag -width Q_QUOTAOFFxx
+.Bl -tag -width Q_GETQUOTASIZEx
.It Dv Q_QUOTAON
Enable disk quotas for the file system specified by
.Fa path .
@@ -110,6 +110,17 @@ and
.Fa id
arguments are unused.
Only the super-user may turn quotas off.
+.It Dv Q_GETQUOTASIZE
+Get the wordsize used to represent the quotas for the user or group
+(as determined by the command type).
+Possible values are 32 for the old-style quota file
+and 64 for the new-style quota file.
+The
+.Fa addr
+argument is a pointer to an integer into which the size is stored.
+The identifier
+.Fa id
+is not used.
.It Dv Q_GETQUOTA
Get disk quota limits and current usage for the user or group
(as determined by the command type) with identifier
@@ -177,9 +188,11 @@ The
argument
or the command type is invalid.
In
-.Dv Q_GETQUOTA
-and
+.Dv Q_GETQUOTASIZE ,
+.Dv Q_GETQUOTA ,
.Dv Q_SETQUOTA ,
+and
+.Dv Q_SETUSE ,
quotas are not currently enabled for this file system.
.Pp
The
@@ -208,7 +221,8 @@ Too many symbolic links were encountered in translating a pathname.
.It Bq Er EROFS
In
.Dv Q_QUOTAON ,
-the quota file resides on a read-only file system.
+either the file system on which quotas are to be enabled is mounted read-only
+or the quota file resides on a read-only file system.
.It Bq Er EIO
An
.Tn I/O
diff --git a/lib/libutil/quotafile.c b/lib/libutil/quotafile.c
index ab57d66..0fda5f6 100644
--- a/lib/libutil/quotafile.c
+++ b/lib/libutil/quotafile.c
@@ -129,11 +129,9 @@ quota_open(struct fstab *fs, int quotatype, int openflags)
goto error;
qf->dev = st.st_dev;
serrno = hasquota(fs, quotatype, qf->qfname, sizeof(qf->qfname));
- qcmd = QCMD(Q_GETQUOTA, quotatype);
- if (quotactl(fs->fs_file, qcmd, 0, &dqh) == 0) {
- qf->wordsize = 64;
+ qcmd = QCMD(Q_GETQUOTASIZE, quotatype);
+ if (quotactl(qf->fsname, qcmd, 0, &qf->wordsize) == 0)
return (qf);
- }
if (serrno == 0) {
errno = EOPNOTSUPP;
goto error;
@@ -250,18 +248,22 @@ int
quota_maxid(struct quotafile *qf)
{
struct stat st;
+ int maxid;
if (stat(qf->qfname, &st) < 0)
return (0);
switch (qf->wordsize) {
case 32:
- return (st.st_size / sizeof(struct dqblk32) - 1);
+ maxid = st.st_size / sizeof(struct dqblk32) - 1;
+ break;
case 64:
- return (st.st_size / sizeof(struct dqblk64) - 2);
+ maxid = st.st_size / sizeof(struct dqblk64) - 2;
+ break;
default:
- return (0);
+ maxid = 0;
+ break;
}
- /* not reached */
+ return (maxid > 0 ? maxid : 0);
}
static int
@@ -395,10 +397,6 @@ quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id)
struct dqblk dqbuf;
int qcmd;
- if ((qf->accmode & O_RDWR) != O_RDWR) {
- errno = EBADF;
- return (-1);
- }
if (qf->fd == -1) {
qcmd = QCMD(Q_SETUSE, qf->quotatype);
return (quotactl(qf->fsname, qcmd, id, dqb));
@@ -406,6 +404,10 @@ quota_write_usage(struct quotafile *qf, struct dqblk *dqb, int id)
/*
* Have to do read-modify-write of quota in file.
*/
+ if ((qf->accmode & O_RDWR) != O_RDWR) {
+ errno = EBADF;
+ return (-1);
+ }
if (quota_read(qf, &dqbuf, id) != 0)
return (-1);
/*
@@ -443,10 +445,6 @@ quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
struct dqblk dqbuf;
int qcmd;
- if ((qf->accmode & O_RDWR) != O_RDWR) {
- errno = EBADF;
- return (-1);
- }
if (qf->fd == -1) {
qcmd = QCMD(Q_SETQUOTA, qf->quotatype);
return (quotactl(qf->fsname, qcmd, id, dqb));
@@ -454,6 +452,10 @@ quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
/*
* Have to do read-modify-write of quota in file.
*/
+ if ((qf->accmode & O_RDWR) != O_RDWR) {
+ errno = EBADF;
+ return (-1);
+ }
if (quota_read(qf, &dqbuf, id) != 0)
return (-1);
/*
diff --git a/sys/ufs/ufs/quota.h b/sys/ufs/ufs/quota.h
index 82b0170..ca0dcce 100644
--- a/sys/ufs/ufs/quota.h
+++ b/sys/ufs/ufs/quota.h
@@ -88,6 +88,7 @@
#define Q_GETQUOTA 0x0700 /* get limits and usage (64-bit version) */
#define Q_SETQUOTA 0x0800 /* set limits and usage (64-bit version) */
#define Q_SETUSE 0x0900 /* set usage (64-bit version) */
+#define Q_GETQUOTASIZE 0x0A00 /* get bit-size of quota file fields */
/*
* The following structure defines the format of the disk quota file
@@ -235,6 +236,7 @@ int setuse32(struct thread *, struct mount *, u_long, int, void *);
int getquota(struct thread *, struct mount *, u_long, int, void *);
int setquota(struct thread *, struct mount *, u_long, int, void *);
int setuse(struct thread *, struct mount *, u_long, int, void *);
+int getquotasize(struct thread *, struct mount *, u_long, int, void *);
vfs_quotactl_t ufs_quotactl;
#else /* !_KERNEL */
diff --git a/sys/ufs/ufs/ufs_quota.c b/sys/ufs/ufs/ufs_quota.c
index 5b1da50..c516189 100644
--- a/sys/ufs/ufs/ufs_quota.c
+++ b/sys/ufs/ufs/ufs_quota.c
@@ -508,6 +508,9 @@ quotaon(struct thread *td, struct mount *mp, int type, void *fname)
if (error)
return (error);
+ if (mp->mnt_flag & MNT_RDONLY)
+ return (EROFS);
+
ump = VFSTOUFS(mp);
dq = NODQUOT;
@@ -534,7 +537,9 @@ quotaon(struct thread *td, struct mount *mp, int type, void *fname)
return (EALREADY);
}
ump->um_qflags[type] |= QTF_OPENING|QTF_CLOSING;
+ UFS_UNLOCK(ump);
if ((error = dqopen(vp, ump, type)) != 0) {
+ UFS_LOCK(ump);
ump->um_qflags[type] &= ~(QTF_OPENING|QTF_CLOSING);
UFS_UNLOCK(ump);
(void) vn_close(vp, FREAD|FWRITE, td->td_ucred, td);
@@ -544,7 +549,6 @@ quotaon(struct thread *td, struct mount *mp, int type, void *fname)
MNT_ILOCK(mp);
mp->mnt_flag |= MNT_QUOTA;
MNT_IUNLOCK(mp);
- UFS_UNLOCK(ump);
vpp = &ump->um_quotas[type];
if (*vpp != vp)
@@ -989,6 +993,30 @@ setuse(struct thread *td, struct mount *mp, u_long id, int type, void *addr)
}
/*
+ * Q_GETQUOTASIZE - get bit-size of quota file fields
+ */
+int
+getquotasize(struct thread *td, struct mount *mp, u_long id, int type,
+ void *sizep)
+{
+ struct ufsmount *ump = VFSTOUFS(mp);
+ int bitsize;
+
+ UFS_LOCK(ump);
+ if (ump->um_quotas[type] == NULLVP ||
+ (ump->um_qflags[type] & QTF_CLOSING)) {
+ UFS_UNLOCK(ump);
+ return (EINVAL);
+ }
+ if ((ump->um_qflags[type] & QTF_64BIT) != 0)
+ bitsize = 64;
+ else
+ bitsize = 32;
+ UFS_UNLOCK(ump);
+ return (copyout(&bitsize, sizep, sizeof(int)));
+}
+
+/*
* Q_SYNC - sync quota files to disk.
*/
int
@@ -1163,12 +1191,17 @@ dqopen(struct vnode *vp, struct ufsmount *ump, int type)
return (0);
}
+ UFS_LOCK(ump);
if (strcmp(dqh.dqh_magic, Q_DQHDR64_MAGIC) == 0 &&
be32toh(dqh.dqh_version) == Q_DQHDR64_VERSION &&
be32toh(dqh.dqh_hdrlen) == (uint32_t)sizeof(struct dqhdr64) &&
- be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64))
+ be32toh(dqh.dqh_reclen) == (uint32_t)sizeof(struct dqblk64)) {
+ /* XXX: what if the magic matches, but the sizes are wrong? */
ump->um_qflags[type] |= QTF_64BIT;
- /* XXX: what if the magic matches, but the sizes are wrong? */
+ } else {
+ ump->um_qflags[type] &= ~QTF_64BIT;
+ }
+ UFS_UNLOCK(ump);
return (0);
}
diff --git a/sys/ufs/ufs/ufs_vfsops.c b/sys/ufs/ufs/ufs_vfsops.c
index 3abd5eb..0eeb14f 100644
--- a/sys/ufs/ufs/ufs_vfsops.c
+++ b/sys/ufs/ufs/ufs_vfsops.c
@@ -151,6 +151,10 @@ ufs_quotactl(mp, cmds, id, arg)
error = getquota(td, mp, id, type, arg);
break;
+ case Q_GETQUOTASIZE:
+ error = getquotasize(td, mp, id, type, arg);
+ break;
+
case Q_SYNC:
error = qsync(mp);
break;
diff --git a/usr.bin/quota/Makefile b/usr.bin/quota/Makefile
index a479402..26585ae 100644
--- a/usr.bin/quota/Makefile
+++ b/usr.bin/quota/Makefile
@@ -3,6 +3,7 @@
PROG= quota
BINOWN= root
+BINMODE=4555
DPADD= ${LIBRPCSVC} ${LIBUTIL}
LDADD= -lrpcsvc -lutil
diff --git a/usr.sbin/repquota/repquota.c b/usr.sbin/repquota/repquota.c
index f90269f..8fdea20 100644
--- a/usr.sbin/repquota/repquota.c
+++ b/usr.sbin/repquota/repquota.c
@@ -224,7 +224,7 @@ repquota(struct fstab *fs, int type)
printf("User%*s used soft hard grace used soft hard grace\n",
max(MAXLOGNAME - 1, 10), " ");
maxid = quota_maxid(qf);
- for (id = 0; id < maxid; id++) {
+ for (id = 0; id <= maxid; id++) {
if (quota_read(qf, &dqbuf, id) != 0)
break;
if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0)
OpenPOWER on IntegriCloud