diff options
author | Yang Lin <lin.a.yang@intel.com> | 2012-05-30 19:43:21 +0800 |
---|---|---|
committer | Yang Lin <lin.a.yang@intel.com> | 2012-05-30 19:43:21 +0800 |
commit | 8c82de96cd23e4823a2d29eb2de2295c0866b0c9 (patch) | |
tree | 4c255e87442eb17f710f1674e13303ff56be0c7a /quotaio_v1.c | |
download | quota-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.c | 389 |
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... */ +} |