/* * 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); }
/* * Update a specified quota file. */ int update(const char *fsname, struct quotafile *qf, int type) { struct fileusage *fup; u_long id, lastid, highid = 0; struct dqblk dqbuf; struct stat sb; static struct dqblk zerodqbuf; static struct fileusage zerofileusage; /* * Scan the on-disk quota file and record any usage changes. */ lastid = quota_maxid(qf); for (id = 0; id <= lastid; id++) { if (quota_read(qf, &dqbuf, id) < 0) dqbuf = zerodqbuf; if ((fup = lookup(id, type)) == NULL) fup = &zerofileusage; if (fup->fu_curinodes || fup->fu_curblocks || dqbuf.dqb_bsoftlimit || dqbuf.dqb_bhardlimit || dqbuf.dqb_isoftlimit || dqbuf.dqb_ihardlimit) highid = id; if (dqbuf.dqb_curinodes == fup->fu_curinodes && dqbuf.dqb_curblocks == fup->fu_curblocks) { fup->fu_curinodes = 0; fup->fu_curblocks = 0; continue; } printchanges(fsname, type, &dqbuf, fup, id); dqbuf.dqb_curinodes = fup->fu_curinodes; dqbuf.dqb_curblocks = fup->fu_curblocks; (void) quota_write_usage(qf, &dqbuf, id); fup->fu_curinodes = 0; fup->fu_curblocks = 0; } /* * Walk the hash table looking for ids with non-zero usage * that are not currently recorded in the quota file. E.g. * ids that are past the end of the current file. */ for (id = 0; id < FUHASH; id++) { for (fup = fuhead[type][id]; fup != NULL; fup = fup->fu_next) { if (fup->fu_id <= lastid) continue; if (fup->fu_curinodes == 0 && fup->fu_curblocks == 0) continue; bzero(&dqbuf, sizeof(struct dqblk)); if (fup->fu_id > highid) highid = fup->fu_id; printchanges(fsname, type, &dqbuf, fup, fup->fu_id); dqbuf.dqb_curinodes = fup->fu_curinodes; dqbuf.dqb_curblocks = fup->fu_curblocks; (void) quota_write_usage(qf, &dqbuf, fup->fu_id); fup->fu_curinodes = 0; fup->fu_curblocks = 0; } } /* * If this is old format file, then size may be smaller, * so ensure that we only truncate when it will make things * smaller, and not if it will grow an old format file. */ if (highid < lastid && stat(quota_qfname(qf), &sb) == 0 && sb.st_size > (((off_t)highid + 2) * sizeof(struct dqblk))) truncate(quota_qfname(qf), (((off_t)highid + 2) * sizeof(struct dqblk))); return (0); }
int repquota(struct fstab *fs, int type) { struct fileusage *fup; struct quotafile *qf; u_long id, maxid; struct dqblk dqbuf; static int multiple = 0; if ((qf = quota_open(fs, type, O_RDONLY)) == NULL) { if (vflag && !aflag) { if (multiple++) printf("\n"); fprintf(stdout, "*** No %s quotas on %s (%s)\n", qfextension[type], fs->fs_file, fs->fs_spec); return(1); } return(0); } if (multiple++) printf("\n"); if (vflag) fprintf(stdout, "*** Report for %s quotas on %s (%s)\n", qfextension[type], fs->fs_file, fs->fs_spec); printf("%*s Block limits File limits\n", max(MAXLOGNAME - 1, 10), " "); 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++) { if (quota_read(qf, &dqbuf, id) != 0) break; if (dqbuf.dqb_curinodes == 0 && dqbuf.dqb_curblocks == 0) continue; if ((fup = lookup(id, type)) == 0) fup = addid(id, type, (char *)0); printf("%-*s ", max(MAXLOGNAME - 1, 10), fup->fu_name); printf("%c%c", dqbuf.dqb_bsoftlimit && dqbuf.dqb_curblocks >= dqbuf.dqb_bsoftlimit ? '+' : '-', dqbuf.dqb_isoftlimit && dqbuf.dqb_curinodes >= dqbuf.dqb_isoftlimit ? '+' : '-'); prthumanval(dqbuf.dqb_curblocks); prthumanval(dqbuf.dqb_bsoftlimit); prthumanval(dqbuf.dqb_bhardlimit); printf(" %6s", dqbuf.dqb_bsoftlimit && dqbuf.dqb_curblocks >= dqbuf.dqb_bsoftlimit ? timeprt(dqbuf.dqb_btime) : "-"); printf(" %7ju %7ju %7ju %6s\n", (uintmax_t)dqbuf.dqb_curinodes, (uintmax_t)dqbuf.dqb_isoftlimit, (uintmax_t)dqbuf.dqb_ihardlimit, dqbuf.dqb_isoftlimit && dqbuf.dqb_curinodes >= dqbuf.dqb_isoftlimit ? timeprt(dqbuf.dqb_itime) : "-"); } quota_close(qf); return (0); }