From b1367bfe2c1e060d7d0e30a02898e30ee01f8fff Mon Sep 17 00:00:00 2001 From: mpp Date: Sun, 4 Feb 2007 01:41:32 +0000 Subject: If quotas are not currently enabled for a file system, edquota -p will operate directly on the quota file. It will incorrectly write the prototype user's usage information for each new quota it sets. Fixed to read in the current quota information and update the file correctly. If quotas are enabled the kernel handles this case fine. PR: bin/15410 --- usr.sbin/edquota/edquota.c | 71 ++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 63 insertions(+), 8 deletions(-) (limited to 'usr.sbin/edquota') diff --git a/usr.sbin/edquota/edquota.c b/usr.sbin/edquota/edquota.c index 1edca4a..a333314 100644 --- a/usr.sbin/edquota/edquota.c +++ b/usr.sbin/edquota/edquota.c @@ -375,7 +375,13 @@ getprivs(id, quotatype, fspath) getentry(quotagroup, GRPQUOTA)); (void) fchmod(fd, 0640); } - lseek(fd, (long)(id * sizeof(struct dqblk)), L_SET); + if (lseek(fd, (off_t)id * sizeof(struct dqblk), + L_SET) < 0) { + warn("seek error on %s", qfpathname); + close(fd); + free(qup); + continue; + } switch (read(fd, &qup->dqblk, sizeof(struct dqblk))) { case 0: /* EOF */ /* @@ -421,21 +427,70 @@ putprivs(id, quotatype, quplist) { register struct quotause *qup; int qcmd, fd; + struct dqblk dqbuf; qcmd = QCMD(Q_SETQUOTA, quotatype); for (qup = quplist; qup; qup = qup->next) { if (quotactl(qup->fsname, qcmd, id, &qup->dqblk) == 0) continue; - if ((fd = open(qup->qfname, O_WRONLY)) < 0) { + if ((fd = open(qup->qfname, O_RDWR)) < 0) { warn("%s", qup->qfname); - } else { - lseek(fd, (long)id * (long)sizeof (struct dqblk), 0); - if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != - sizeof (struct dqblk)) { - warn("%s", qup->qfname); - } + continue; + } + if (lseek(fd, (off_t)id * sizeof(struct dqblk), L_SET) < 0) { + warn("seek error on %s", qup->qfname); + close(fd); + continue; + } + switch (read(fd, &dqbuf, sizeof(struct dqblk))) { + case 0: /* EOF */ + /* + * Convert implicit 0 quota (EOF) + * into an explicit one (zero'ed dqblk) + */ + bzero(&dqbuf, sizeof(struct dqblk)); + break; + + case sizeof(struct dqblk): /* OK */ + break; + + default: /* ERROR */ + warn("read error in %s", qup->qfname); close(fd); + continue; } + /* + * Reset time limit if have a soft limit and were + * previously under it, but are now over it + * or if there previously was no soft limit, but + * now have one and are over it. + */ + if (dqbuf.dqb_bsoftlimit && id != 0 && + dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit && + dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) + qup->dqblk.dqb_btime = 0; + if (dqbuf.dqb_bsoftlimit == 0 && id != 0 && + dqbuf.dqb_curblocks >= qup->dqblk.dqb_bsoftlimit) + qup->dqblk.dqb_btime = 0; + if (dqbuf.dqb_isoftlimit && id != 0 && + dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit && + dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) + qup->dqblk.dqb_itime = 0; + if (dqbuf.dqb_isoftlimit == 0 && id !=0 && + dqbuf.dqb_curinodes >= qup->dqblk.dqb_isoftlimit) + qup->dqblk.dqb_itime = 0; + qup->dqblk.dqb_curinodes = dqbuf.dqb_curinodes; + qup->dqblk.dqb_curblocks = dqbuf.dqb_curblocks; + if (lseek(fd, (off_t)id * sizeof(struct dqblk), L_SET) < 0) { + warn("seek error on %s", qup->qfname); + close(fd); + continue; + } + if (write(fd, &qup->dqblk, sizeof (struct dqblk)) != + sizeof (struct dqblk)) { + warn("%s", qup->qfname); + } + close(fd); } } -- cgit v1.1