aboutsummaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorKirk McKusick <mckusick@FreeBSD.org>2009-12-28 22:44:19 +0000
committerKirk McKusick <mckusick@FreeBSD.org>2009-12-28 22:44:19 +0000
commitaee785babde44bcfef1d711653a85896dde7324b (patch)
tree5ca170e00b6c594a0844a3f2d064848cb0cd762b /lib
parent3af26d4abba3ad1858920eedf0710663499167f1 (diff)
downloadsrc-aee785babde44bcfef1d711653a85896dde7324b.tar.gz
src-aee785babde44bcfef1d711653a85896dde7324b.zip
Add and document the quota_convert function which converts between the
old 32-bit and the new 64-bit formats.
Notes
Notes: svn path=/projects/quota64/; revision=201144
Diffstat (limited to 'lib')
-rw-r--r--lib/libutil/libutil.h1
-rw-r--r--lib/libutil/quotafile.334
-rw-r--r--lib/libutil/quotafile.c99
3 files changed, 124 insertions, 10 deletions
diff --git a/lib/libutil/libutil.h b/lib/libutil/libutil.h
index 3a05d9b56f69..7a4dc5670bcb 100644
--- a/lib/libutil/libutil.h
+++ b/lib/libutil/libutil.h
@@ -154,6 +154,7 @@ int quota_check_path(const struct quotafile *, const char *path);
int quota_read(struct quotafile *, struct dqblk *, int);
int quota_write_limits(struct quotafile *, struct dqblk *, int);
int quota_write_usage(struct quotafile *, struct dqblk *, int);
+int quota_convert(struct quotafile *, int);
#endif
__END_DECLS
diff --git a/lib/libutil/quotafile.3 b/lib/libutil/quotafile.3
index d2134c505306..5702cec90762 100644
--- a/lib/libutil/quotafile.3
+++ b/lib/libutil/quotafile.3
@@ -1,6 +1,6 @@
.\"-
-.\" Copyright (c) 2008 Dag-Erling Coïdan Smørgrav
-.\" All rights reserved.
+.\" Copyright (c) 2009 Dag-Erling Coïdan Smørgrav and
+.\" Marshall Kirk McKusick. All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
@@ -25,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd September 26, 2009
+.Dd December 28, 2009
.Dt QUOTAFILE 3
.Os
.Sh NAME
@@ -40,6 +40,7 @@
.Nm quota_qfname
.Nm quota_maxid
.Nm quota_check_path
+.Nm quota_convert
.Nd "Manipulate quotas"
.Sh LIBRARY
.Lb libutil
@@ -72,6 +73,8 @@
.Fn quota_maxid "const struct quotafile *qf"
.Ft int
.Fn quota_check_path "const struct quotafile *qf" "const char *path"
+.Ft int
+.Fn quota_convert "struct quotafile *qf" "int wordsize"
.Sh DESCRIPTION
These functions are designed to simplify access to filesystem quotas.
If quotas are active on a filesystem,
@@ -219,9 +222,23 @@ If the
argument refers to a symbolic link,
.Fn quota_check_path
will follow it.
+.Pp
+The
+.Fn quota_convert
+function converts the quota file associated with its
+.Va qf
+argument to the data size specified by its
+.Va wordsize
+argument.
+The supported wordsize arguments are 32 for the old 32-bit
+quota file format and 64 for the new 64-bit quota file format.
+The
+.Fn quota_convert
+function may only be called to operate on quota files that
+are not currently active.
.Sh IMPLEMENTATION NOTES
-If the underlying quota file is in the old 32-bit format, limit and
-usage values written to the quota file will be clipped to 32 bits.
+If the underlying quota file is in or converted to the old 32-bit format,
+limit and usage values written to the quota file will be clipped to 32 bits.
.Sh RETURN VALUES
If the filesystem has quotas associated with it,
.Fn quota_open
@@ -246,6 +263,7 @@ The
.Fn quota_read ,
.Fn quota_write_limits ,
.Fn quota_write_usage ,
+.Fn quota_convert ,
and
.Fn quota_close
functions return zero on success.
@@ -259,13 +277,13 @@ to indicate the error.
.Xr quota.group 5
.Sh HISTORY
The
-.Nm
+.Nm quotafile
functions first appeared in
-.Fx 8.0 .
+.Fx 8.1 .
.Sh AUTHORS
.An -nosplit
The
-.Nm
+.Nm quotafile
functions and this manual page were written by
.An Dag-Erling Sm\(/orgrav Aq des@FreeBSD.org
and
diff --git a/lib/libutil/quotafile.c b/lib/libutil/quotafile.c
index 652d95a290fc..ab57d662bdc7 100644
--- a/lib/libutil/quotafile.c
+++ b/lib/libutil/quotafile.c
@@ -255,9 +255,9 @@ quota_maxid(struct quotafile *qf)
return (0);
switch (qf->wordsize) {
case 32:
- return (st.st_size / sizeof(struct dqblk32));
+ return (st.st_size / sizeof(struct dqblk32) - 1);
case 64:
- return (st.st_size / sizeof(struct dqblk64) - 1);
+ return (st.st_size / sizeof(struct dqblk64) - 2);
default:
return (0);
}
@@ -494,3 +494,98 @@ quota_write_limits(struct quotafile *qf, struct dqblk *dqb, int id)
}
/* not reached */
}
+
+/*
+ * Convert a quota file from one format to another.
+ */
+int
+quota_convert(struct quotafile *qf, int wordsize)
+{
+ struct quotafile *newqf;
+ struct dqhdr64 dqh;
+ struct dqblk dqblk;
+ struct group *grp;
+ int serrno, maxid, id, fd;
+
+ /*
+ * Quotas must not be active and quotafile must be open
+ * for reading and writing.
+ */
+ if ((qf->accmode & O_RDWR) != O_RDWR || qf->fd == -1) {
+ errno = EBADF;
+ return (-1);
+ }
+ if ((wordsize != 32 && wordsize != 64) ||
+ wordsize == qf->wordsize) {
+ errno = EINVAL;
+ return (-1);
+ }
+ maxid = quota_maxid(qf);
+ if ((newqf = calloc(1, sizeof(*qf))) == NULL) {
+ errno = ENOMEM;
+ return (-1);
+ }
+ *newqf = *qf;
+ snprintf(newqf->qfname, MAXPATHLEN + 1, "%s_%d.orig", qf->qfname,
+ qf->wordsize);
+ if (rename(qf->qfname, newqf->qfname) < 0) {
+ free(newqf);
+ return (-1);
+ }
+ if ((newqf->fd = open(qf->qfname, O_RDWR|O_CREAT|O_TRUNC, 0)) < 0) {
+ serrno = errno;
+ goto error;
+ }
+ newqf->wordsize = wordsize;
+ if (wordsize == 64) {
+ memset(&dqh, 0, sizeof(dqh));
+ memcpy(dqh.dqh_magic, Q_DQHDR64_MAGIC, sizeof(dqh.dqh_magic));
+ dqh.dqh_version = htobe32(Q_DQHDR64_VERSION);
+ dqh.dqh_hdrlen = htobe32(sizeof(struct dqhdr64));
+ dqh.dqh_reclen = htobe32(sizeof(struct dqblk64));
+ if (write(newqf->fd, &dqh, sizeof(dqh)) != sizeof(dqh)) {
+ serrno = errno;
+ goto error;
+ }
+ }
+ grp = getgrnam(QUOTAGROUP);
+ fchown(newqf->fd, 0, grp ? grp->gr_gid : 0);
+ fchmod(newqf->fd, 0640);
+ for (id = 0; id <= maxid; id++) {
+ if ((quota_read(qf, &dqblk, id)) < 0)
+ break;
+ switch (newqf->wordsize) {
+ case 32:
+ if ((quota_write32(newqf, &dqblk, id)) < 0)
+ break;
+ continue;
+ case 64:
+ if ((quota_write64(newqf, &dqblk, id)) < 0)
+ break;
+ continue;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ }
+ if (id < maxid) {
+ serrno = errno;
+ goto error;
+ }
+ /*
+ * Update the passed in quotafile to reference the new file
+ * of the converted format size.
+ */
+ fd = qf->fd;
+ qf->fd = newqf->fd;
+ newqf->fd = fd;
+ qf->wordsize = newqf->wordsize;
+ quota_close(newqf);
+ return (0);
+error:
+ /* put back the original file */
+ (void) rename(newqf->qfname, qf->qfname);
+ quota_close(newqf);
+ errno = serrno;
+ return (-1);
+}