summaryrefslogtreecommitdiff
path: root/quotaio_v1.c
diff options
context:
space:
mode:
authorYang Lin <lin.a.yang@intel.com>2012-05-30 19:43:21 +0800
committerYang Lin <lin.a.yang@intel.com>2012-05-30 19:43:21 +0800
commit8c82de96cd23e4823a2d29eb2de2295c0866b0c9 (patch)
tree4c255e87442eb17f710f1674e13303ff56be0c7a /quotaio_v1.c
downloadquota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.tar.gz
quota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.tar.bz2
quota-8c82de96cd23e4823a2d29eb2de2295c0866b0c9.zip
Initial commit to Gerrittizen/20120530.11.0_branch1.0
Diffstat (limited to 'quotaio_v1.c')
-rw-r--r--quotaio_v1.c389
1 files changed, 389 insertions, 0 deletions
diff --git a/quotaio_v1.c b/quotaio_v1.c
new file mode 100644
index 0000000..0edbc16
--- /dev/null
+++ b/quotaio_v1.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 1980, 1990 Regents of the University of California. All
+ * rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by Robert Elz at
+ * The University of Melbourne.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met: 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer. 2.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution. 3. All advertising
+ * materials mentioning features or use of this software must display the
+ * following acknowledgement: This product includes software developed by the
+ * University of California, Berkeley and its contributors. 4. Neither the
+ * name of the University nor the names of its contributors may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include "pot.h"
+#include "common.h"
+#include "quotaio_v1.h"
+#include "dqblk_v1.h"
+#include "quotaio.h"
+#include "quotasys.h"
+#include "quotaio_generic.h"
+
+static int v1_check_file(int fd, int type, int fmt);
+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);
+static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id);
+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,
+read_dquot: v1_read_dquot,
+commit_dquot: v1_commit_dquot,
+scan_dquots: v1_scan_dquots,
+};
+
+/*
+ * Copy dquot from disk to memory
+ */
+static inline void v1_disk2memdqblk(struct util_dqblk *m, struct v1_disk_dqblk *d)
+{
+ m->dqb_ihardlimit = d->dqb_ihardlimit;
+ m->dqb_isoftlimit = d->dqb_isoftlimit;
+ m->dqb_bhardlimit = d->dqb_bhardlimit;
+ m->dqb_bsoftlimit = d->dqb_bsoftlimit;
+ m->dqb_curinodes = d->dqb_curinodes;
+ m->dqb_curspace = ((qsize_t)d->dqb_curblocks) * V1_DQBLK_SIZE;
+ m->dqb_itime = d->dqb_itime;
+ m->dqb_btime = d->dqb_btime;
+}
+
+/*
+ * Copy dquot from memory to disk
+ */
+static inline void v1_mem2diskdqblk(struct v1_disk_dqblk *d, struct util_dqblk *m)
+{
+ d->dqb_ihardlimit = m->dqb_ihardlimit;
+ d->dqb_isoftlimit = m->dqb_isoftlimit;
+ d->dqb_bhardlimit = m->dqb_bhardlimit;
+ d->dqb_bsoftlimit = m->dqb_bsoftlimit;
+ d->dqb_curinodes = m->dqb_curinodes;
+ d->dqb_curblocks = m->dqb_curspace >> V1_DQBLK_SIZE_BITS;
+ d->dqb_itime = m->dqb_itime;
+ d->dqb_btime = m->dqb_btime;
+}
+
+/* Convert kernel quotablock format to utility one */
+static inline void v1_kern2utildqblk(struct util_dqblk *u, struct v1_kern_dqblk *k)
+{
+ u->dqb_ihardlimit = k->dqb_ihardlimit;
+ u->dqb_isoftlimit = k->dqb_isoftlimit;
+ u->dqb_bhardlimit = k->dqb_bhardlimit;
+ u->dqb_bsoftlimit = k->dqb_bsoftlimit;
+ u->dqb_curinodes = k->dqb_curinodes;
+ u->dqb_curspace = ((qsize_t)k->dqb_curblocks) << V1_DQBLK_SIZE_BITS;
+ u->dqb_itime = k->dqb_itime;
+ u->dqb_btime = k->dqb_btime;
+}
+
+/* Convert utility quotablock format to kernel one */
+static inline void v1_util2kerndqblk(struct v1_kern_dqblk *k, struct util_dqblk *u)
+{
+ k->dqb_ihardlimit = u->dqb_ihardlimit;
+ k->dqb_isoftlimit = u->dqb_isoftlimit;
+ k->dqb_bhardlimit = u->dqb_bhardlimit;
+ k->dqb_bsoftlimit = u->dqb_bsoftlimit;
+ k->dqb_curinodes = u->dqb_curinodes;
+ k->dqb_curblocks = (u->dqb_curspace + V1_DQBLK_SIZE - 1) >> V1_DQBLK_SIZE_BITS;
+ k->dqb_itime = u->dqb_itime;
+ k->dqb_btime = u->dqb_btime;
+}
+
+/*
+ * Check whether quotafile is in our format
+ */
+static int v1_check_file(int fd, int type, int fmt)
+{
+ 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)) {
+ if (kernel_iface == IFACE_GENERIC) {
+ if (vfs_get_info(h) < 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) {
+ 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 {
+ struct v1_disk_dqblk ddqblk;
+
+ lseek(h->qh_fd, 0, SEEK_SET);
+ if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
+ return -1;
+ h->qh_info.dqi_bgrace = ddqblk.dqb_btime;
+ h->qh_info.dqi_igrace = ddqblk.dqb_itime;
+ }
+ if (!h->qh_info.dqi_bgrace)
+ h->qh_info.dqi_bgrace = MAX_DQ_TIME;
+ if (!h->qh_info.dqi_igrace)
+ h->qh_info.dqi_igrace = MAX_IQ_TIME;
+
+ return 0;
+}
+
+/*
+ * Initialize new quotafile
+ */
+static int v1_new_io(struct quota_handle *h)
+{
+ struct v1_disk_dqblk ddqblk;
+
+ /* Write at least roots dquot with grace times */
+ memset(&ddqblk, 0, sizeof(ddqblk));
+ ddqblk.dqb_btime = MAX_DQ_TIME;
+ ddqblk.dqb_itime = MAX_IQ_TIME;
+ h->qh_info.dqi_bgrace = MAX_DQ_TIME;
+ h->qh_info.dqi_igrace = MAX_IQ_TIME;
+ lseek(h->qh_fd, 0, SEEK_SET);
+ if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
+ return -1;
+ return 0;
+}
+
+/*
+ * Write information (grace times to file)
+ */
+static int v1_write_info(struct quota_handle *h)
+{
+ if (QIO_RO(h)) {
+ errstr(_("Trying to write info to readonly quotafile on %s.\n"), h->qh_quotadev);
+ errno = EPERM;
+ return -1;
+ }
+ if (QIO_ENABLED(h)) {
+ 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;
+ }
+ }
+ else {
+ struct v1_disk_dqblk ddqblk;
+
+ lseek(h->qh_fd, 0, SEEK_SET);
+ if (read(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
+ return -1;
+ ddqblk.dqb_btime = h->qh_info.dqi_bgrace;
+ ddqblk.dqb_itime = h->qh_info.dqi_igrace;
+ lseek(h->qh_fd, 0, SEEK_SET);
+ if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Read a dqblk struct from the quotafile.
+ * User can use 'errno' to detect errstr.
+ */
+static struct dquot *v1_read_dquot(struct quota_handle *h, qid_t id)
+{
+ struct v1_disk_dqblk ddqblk;
+ struct dquot *dquot = get_empty_dquot();
+
+ dquot->dq_id = id;
+ dquot->dq_h = h;
+ if (QIO_ENABLED(h)) { /* Does kernel use the file? */
+ 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;
+ }
+ v1_kern2utildqblk(&dquot->dq_dqb, &kdqblk);
+ }
+ }
+ else {
+ lseek(h->qh_fd, (long)V1_DQOFF(id), SEEK_SET);
+ switch (read(h->qh_fd, &ddqblk, sizeof(ddqblk))) {
+ case 0: /* EOF */
+ /*
+ * Convert implicit 0 quota (EOF) into an
+ * explicit one (zero'ed dqblk)
+ */
+ memset(&dquot->dq_dqb, 0, sizeof(struct util_dqblk));
+ break;
+ case sizeof(struct v1_disk_dqblk): /* OK */
+ v1_disk2memdqblk(&dquot->dq_dqb, &ddqblk);
+ break;
+ default: /* ERROR */
+ free(dquot);
+ return NULL;
+ }
+ }
+ return dquot;
+}
+
+/*
+ * Write a dqblk struct to the quotafile.
+ * User can process use 'errno' to detect errstr
+ */
+static int v1_commit_dquot(struct dquot *dquot, int flags)
+{
+ struct v1_disk_dqblk ddqblk;
+ struct quota_handle *h = dquot->dq_h;
+
+ if (QIO_RO(h)) {
+ errstr(_("Trying to write quota to readonly quotafile on %s\n"), h->qh_quotadev);
+ errno = EPERM;
+ return -1;
+ }
+ if (QIO_ENABLED(h)) { /* Kernel uses same file? */
+ 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 if (flags & COMMIT_TIMES) {
+ errno = EINVAL;
+ return -1;
+ }
+ 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);
+ lseek(h->qh_fd, (long)V1_DQOFF(dquot->dq_id), SEEK_SET);
+ if (write(h->qh_fd, &ddqblk, sizeof(ddqblk)) != sizeof(ddqblk))
+ return -1;
+ }
+ return 0;
+}
+
+/*
+ * Scan all dquots in file and call callback on each
+ */
+#define SCANBUFSIZE 256
+
+static int v1_scan_dquots(struct quota_handle *h, int (*process_dquot) (struct dquot *, char *))
+{
+ int rd, scanbufpos = 0, scanbufsize = 0;
+ char scanbuf[sizeof(struct v1_disk_dqblk)*SCANBUFSIZE];
+ struct v1_disk_dqblk *ddqblk;
+ struct dquot *dquot = get_empty_dquot();
+ qid_t id = 0;
+
+ if (QIO_ENABLED(h)) /* Kernel uses same file? */
+ if (quotactl(QCMD((kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC, h->qh_type),
+ h->qh_quotadev, 0, NULL) < 0)
+ die(4, _("Cannot sync quotas on device %s: %s\n"), h->qh_quotadev,
+ strerror(errno));
+ memset(dquot, 0, sizeof(*dquot));
+ dquot->dq_h = h;
+ lseek(h->qh_fd, 0, SEEK_SET);
+ for(id = 0; ; id++, scanbufpos++) {
+ if (scanbufpos >= scanbufsize) {
+ rd = read(h->qh_fd, scanbuf, sizeof(scanbuf));
+ if (rd < 0 || rd % sizeof(struct v1_disk_dqblk))
+ goto out_err;
+ if (!rd)
+ break;
+ scanbufpos = 0;
+ scanbufsize = rd / sizeof(struct v1_disk_dqblk);
+ }
+ ddqblk = ((struct v1_disk_dqblk *)scanbuf) + scanbufpos;
+ if ((ddqblk->dqb_ihardlimit | ddqblk->dqb_isoftlimit |
+ ddqblk->dqb_bhardlimit | ddqblk->dqb_bsoftlimit |
+ ddqblk->dqb_curblocks | ddqblk->dqb_curinodes |
+ ddqblk->dqb_itime | ddqblk->dqb_btime) == 0)
+ continue;
+ v1_disk2memdqblk(&dquot->dq_dqb, ddqblk);
+ dquot->dq_id = id;
+ if ((rd = process_dquot(dquot, NULL)) < 0) {
+ free(dquot);
+ return rd;
+ }
+ }
+ if (!rd) { /* EOF? */
+ free(dquot);
+ return 0;
+ }
+out_err:
+ free(dquot);
+ return -1; /* Some read errstr... */
+}