Convert quotacheck to use new quotafile functions in libutil.

Still to come, conversion between 64-bit and 32-bit quotafile formats.
This commit is contained in:
Kirk McKusick 2009-12-27 06:28:01 +00:00
parent c3616249ab
commit 3af26d4abb
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/projects/quota64/; revision=201039
4 changed files with 109 additions and 236 deletions

View File

@ -5,6 +5,8 @@ PROG= quotacheck
SRCS= quotacheck.c preen.c fsutil.c utilities.c
WARNS?= 2
MAN= quotacheck.8
DPADD= ${LIBUTIL}
LDADD= -lutil
.PATH: ${.CURDIR}/../fsck ${.CURDIR}/../fsck_ffs

View File

@ -45,9 +45,13 @@ __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
#include <sys/wait.h>
#include <sys/queue.h>
#include <ufs/ufs/quota.h>
#include <err.h>
#include <ctype.h>
#include <fcntl.h>
#include <fstab.h>
#include <libutil.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
@ -58,9 +62,9 @@ __RCSID("$NetBSD: preen.c,v 1.18 1998/07/26 20:02:36 mycroft Exp $");
struct partentry {
TAILQ_ENTRY(partentry) p_entries;
char *p_devname; /* device name */
char *p_mntpt; /* mount point */
char *p_type; /* file system type */
struct quotaname *p_quota; /* quota file info ptr */
const char *p_mntpt; /* mount point */
struct quotafile *p_qfu; /* user quota file info ptr */
struct quotafile *p_qfg; /* group quota file info */
};
TAILQ_HEAD(part, partentry) badh;
@ -75,21 +79,19 @@ struct diskentry {
TAILQ_HEAD(disk, diskentry) diskh;
static struct diskentry *finddisk(const char *);
static void addpart(const char *, const char *, const char *,
struct quotaname *);
static void addpart(struct fstab *, struct quotafile *, struct quotafile *);
static int startdisk(struct diskentry *);
extern void *emalloc(size_t);
extern char *estrdup(const char *);
int
checkfstab(void)
checkfstab(int uflag, int gflag)
{
struct fstab *fs;
struct diskentry *d, *nextdisk;
struct partentry *p;
int ret, pid, retcode, passno, sumstatus, status, nextpass;
char *name;
struct quotaname *qnp;
struct quotafile *qfu, *qfg;
TAILQ_INIT(&badh);
TAILQ_INIT(&diskh);
@ -104,30 +106,32 @@ checkfstab(void)
return (8);
}
while ((fs = getfsent()) != 0) {
name = fs->fs_spec;
if (fs->fs_passno > passno && fs->fs_passno < nextpass)
nextpass = fs->fs_passno;
if (passno != fs->fs_passno)
continue;
if ((qnp = needchk(fs)) == NULL)
qfu = NULL;
if (uflag)
qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR);
qfg = NULL;
if (gflag)
qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR);
if (qfu == NULL && qfg == NULL)
continue;
if (passno == 1) {
sumstatus = chkquota(name, fs->fs_file, qnp);
sumstatus = chkquota(fs->fs_spec, qfu, qfg);
if (qfu)
quota_close(qfu);
if (qfg)
quota_close(qfg);
if (sumstatus)
return (sumstatus);
continue;
}
if (name == NULL) {
(void) fprintf(stderr,
"BAD DISK NAME %s\n", fs->fs_spec);
sumstatus |= 8;
continue;
}
addpart(fs->fs_vfstype, name, fs->fs_file, qnp);
addpart(fs, qfu, qfg);
}
if (passno == 1)
@ -157,8 +161,8 @@ checkfstab(void)
if (WIFSIGNALED(status)) {
(void) fprintf(stderr,
"%s: %s (%s): EXITED WITH SIGNAL %d\n",
p->p_type, p->p_devname, p->p_mntpt,
"%s: (%s): EXITED WITH SIGNAL %d\n",
p->p_devname, p->p_mntpt,
WTERMSIG(status));
retcode = 8;
}
@ -169,8 +173,11 @@ checkfstab(void)
TAILQ_INSERT_TAIL(&badh, p, p_entries);
sumstatus |= retcode;
} else {
free(p->p_type);
free(p->p_devname);
if (p->p_qfu)
quota_close(p->p_qfu);
if (p->p_qfg)
quota_close(p->p_qfg);
free(p);
}
d->d_pid = 0;
@ -196,8 +203,8 @@ checkfstab(void)
for (; p; p = TAILQ_NEXT(p, p_entries))
(void) fprintf(stderr,
"%s: %s (%s)%s", p->p_type, p->p_devname,
p->p_mntpt, TAILQ_NEXT(p, p_entries) ? ", " : "\n");
"%s: (%s)%s", p->p_devname, p->p_mntpt,
TAILQ_NEXT(p, p_entries) ? ", " : "\n");
return sumstatus;
}
@ -242,23 +249,25 @@ finddisk(const char *name)
}
static void
addpart(const char *type, const char *devname, const char *mntpt,
struct quotaname *qnp)
addpart(struct fstab *fs, struct quotafile *qfu, struct quotafile *qfg)
{
struct diskentry *d = finddisk(devname);
struct diskentry *d = finddisk(fs->fs_spec);
struct partentry *p;
TAILQ_FOREACH(p, &d->d_part, p_entries)
if (strcmp(p->p_devname, devname) == 0) {
warnx("%s in fstab more than once!\n", devname);
if (strcmp(p->p_devname, fs->fs_spec) == 0) {
warnx("%s in fstab more than once!\n", fs->fs_spec);
return;
}
p = emalloc(sizeof(*p));
p->p_devname = estrdup(devname);
p->p_mntpt = estrdup(mntpt);
p->p_type = estrdup(type);
p->p_quota = qnp;
p->p_devname = estrdup(blockcheck(fs->fs_spec));
if (qfu != NULL)
p->p_mntpt = quota_fsname(qfu);
else
p->p_mntpt = quota_fsname(qfg);
p->p_qfu = qfu;
p->p_qfg = qfg;
TAILQ_INSERT_TAIL(&d->d_part, p, p_entries);
}
@ -275,6 +284,6 @@ startdisk(struct diskentry *d)
return (8);
}
if (d->d_pid == 0)
exit(chkquota(p->p_devname, p->p_mntpt, p->p_quota));
exit(chkquota(p->p_devname, p->p_qfu, p->p_qfg));
return (0);
}

View File

@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
#include <fcntl.h>
#include <fstab.h>
#include <grp.h>
#include <libutil.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
@ -115,21 +116,19 @@ int vflag; /* verbose */
int fi; /* open disk file descriptor */
struct fileusage *
addid(u_long, int, char *, char *);
char *blockcheck(char *);
addid(u_long, int, char *, const char *);
void bread(ufs2_daddr_t, char *, long);
void freeinodebuf(void);
union dinode *
getnextinode(ino_t);
int getquotagid(void);
int hasquota(struct fstab *, int, char **);
struct fileusage *
lookup(u_long, int);
struct quotaname *needchk(struct fstab *);
int oneof(char *, char*[], int);
void printchanges(char *, int, struct dqblk *, struct fileusage *, u_long);
void printchanges(const char *, int, struct dqblk *, struct fileusage *,
u_long);
void setinodebuf(ino_t);
int update(char *, char *, int);
int update(const char *, struct quotafile *, int);
void usage(void);
int
@ -138,7 +137,7 @@ main(int argc, char *argv[])
struct fstab *fs;
struct passwd *pw;
struct group *gr;
struct quotaname *qnp;
struct quotafile *qfu, *qfg;
int i, argnum, maxrun, errs, ch;
long done = 0;
char *name;
@ -193,16 +192,27 @@ main(int argc, char *argv[])
if (maxrun > 0)
warnx("the -l option is now deprecated");
if (aflag)
exit(checkfstab());
exit(checkfstab(uflag, gflag));
if (setfsent() == 0)
errx(1, "%s: can't open", FSTAB);
while ((fs = getfsent()) != NULL) {
if (((argnum = oneof(fs->fs_file, argv, argc)) >= 0 ||
(argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
(qnp = needchk(fs)) &&
(argnum = oneof(fs->fs_spec, argv, argc)) >= 0) &&
(name = blockcheck(fs->fs_spec))) {
done |= 1 << argnum;
errs += chkquota(name, fs->fs_file, qnp);
qfu = NULL;
if (uflag)
qfu = quota_open(fs, USRQUOTA, O_CREAT|O_RDWR);
qfg = NULL;
if (gflag)
qfg = quota_open(fs, GRPQUOTA, O_CREAT|O_RDWR);
if (qfu == NULL && qfg == NULL)
continue;
errs += chkquota(name, qfu, qfg);
if (qfu)
quota_close(qfu);
if (qfg)
quota_close(qfg);
}
}
endfsent();
@ -222,32 +232,6 @@ usage(void)
exit(1);
}
struct quotaname *
needchk(struct fstab *fs)
{
struct quotaname *qnp;
char *qfnp;
if (strcmp(fs->fs_vfstype, "ufs") ||
strcmp(fs->fs_type, FSTAB_RW))
return (NULL);
if ((qnp = malloc(sizeof(*qnp))) == NULL)
errx(1, "malloc failed");
qnp->flags = 0;
if (gflag && hasquota(fs, GRPQUOTA, &qfnp)) {
strcpy(qnp->grpqfname, qfnp);
qnp->flags |= HASGRP;
}
if (uflag && hasquota(fs, USRQUOTA, &qfnp)) {
strcpy(qnp->usrqfname, qfnp);
qnp->flags |= HASUSR;
}
if (qnp->flags)
return (qnp);
free(qnp);
return (NULL);
}
/*
* Possible superblock locations ordered from most to least likely.
*/
@ -257,20 +241,25 @@ static int sblock_try[] = SBLOCKSEARCH;
* Scan the specified file system to check quota(s) present on it.
*/
int
chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg)
{
struct fileusage *fup;
union dinode *dp;
int cg, i, mode, errs = 0;
ino_t ino, inosused, userino = 0, groupino = 0;
dev_t dev, userdev = 0, groupdev = 0;
char *cp;
struct stat sb;
const char *mntpt;
char *cp;
if (qnp == NULL)
err(1, "null quota information passed to chkquota()\n");
if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
warn("%s", fsname);
if (qfu != NULL)
mntpt = quota_fsname(qfu);
else if (qfg != NULL)
mntpt = quota_fsname(qfg);
else
err(1, "null quotafile information passed to chkquota()\n");
if ((fi = open(specname, O_RDONLY, 0)) < 0) {
warn("%s", specname);
return (1);
}
if ((stat(mntpt, &sb)) < 0) {
@ -280,21 +269,20 @@ chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
dev = sb.st_dev;
if (vflag) {
(void)printf("*** Checking ");
if (qnp->flags & HASUSR)
(void)printf("%s%s", qfextension[USRQUOTA],
(qnp->flags & HASGRP) ? " and " : "");
if (qnp->flags & HASGRP)
(void)printf("%s", qfextension[GRPQUOTA]);
(void)printf(" quotas for %s (%s)\n", fsname, mntpt);
if (qfu)
(void)printf("user%s", qfg ? " and " : "");
if (qfg)
(void)printf("group");
(void)printf(" quotas for %s (%s)\n", specname, mntpt);
}
if (qnp->flags & HASUSR) {
if (stat(qnp->usrqfname, &sb) == 0) {
if (qfu) {
if (stat(quota_qfname(qfu), &sb) == 0) {
userino = sb.st_ino;
userdev = sb.st_dev;
}
}
if (qnp->flags & HASGRP) {
if (stat(qnp->grpqfname, &sb) == 0) {
if (qfg) {
if (stat(quota_qfname(qfg), &sb) == 0) {
groupino = sb.st_ino;
groupdev = sb.st_dev;
}
@ -382,7 +370,7 @@ chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
if ((ino == userino && dev == userdev) ||
(ino == groupino && dev == groupdev))
continue;
if (qnp->flags & HASGRP) {
if (qfg) {
fup = addid((u_long)DIP(dp, di_gid), GRPQUOTA,
(char *)0, mntpt);
fup->fu_curinodes++;
@ -390,7 +378,7 @@ chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
mode == IFLNK)
fup->fu_curblocks += DIP(dp, di_blocks);
}
if (qnp->flags & HASUSR) {
if (qfu) {
fup = addid((u_long)DIP(dp, di_uid), USRQUOTA,
(char *)0, mntpt);
fup->fu_curinodes++;
@ -401,10 +389,10 @@ chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
}
}
freeinodebuf();
if (qnp->flags & HASUSR)
errs += update(mntpt, qnp->usrqfname, USRQUOTA);
if (qnp->flags & HASGRP)
errs += update(mntpt, qnp->grpqfname, GRPQUOTA);
if (qfu)
errs += update(mntpt, qfu, USRQUOTA);
if (qfg)
errs += update(mntpt, qfg, GRPQUOTA);
close(fi);
(void)fflush(stdout);
return (errs);
@ -414,63 +402,20 @@ chkquota(char *fsname, char *mntpt, struct quotaname *qnp)
* Update a specified quota file.
*/
int
update(char *fsname, char *quotafile, int type)
update(const char *fsname, struct quotafile *qf, int type)
{
struct fileusage *fup;
FILE *qfi, *qfo;
u_long id, lastid, highid = 0;
off_t offset;
int i;
struct dqblk dqbuf;
struct stat sb;
static int warned = 0;
static struct dqblk zerodqbuf;
static struct fileusage zerofileusage;
if ((qfo = fopen(quotafile, "r+")) == NULL) {
if (errno == ENOENT)
qfo = fopen(quotafile, "w+");
if (qfo) {
warnx("creating quota file %s", quotafile);
#define MODE (S_IRUSR|S_IWUSR|S_IRGRP)
(void) fchown(fileno(qfo), getuid(), getquotagid());
(void) fchmod(fileno(qfo), MODE);
} else {
warn("%s", quotafile);
return (1);
}
}
if ((qfi = fopen(quotafile, "r")) == NULL) {
warn("%s", quotafile);
(void) fclose(qfo);
return (1);
}
if (quotactl(fsname, QCMD(Q_SYNC, type), (u_long)0, (caddr_t)0) < 0 &&
errno == EOPNOTSUPP && !warned && vflag) {
warned++;
(void)printf("*** Warning: %s\n",
"Quotas are not compiled into this kernel");
}
if (fstat(fileno(qfi), &sb) < 0) {
warn("Cannot fstat quota file %s\n", quotafile);
(void) fclose(qfo);
(void) fclose(qfi);
return (1);
}
if ((sb.st_size % sizeof(struct dqblk)) != 0)
warn("%s size is not a multiple of dqblk\n", quotafile);
/*
* Scan the on-disk quota file and record any usage changes.
*/
if (sb.st_size != 0)
lastid = (sb.st_size / sizeof(struct dqblk)) - 1;
else
lastid = 0;
for (id = 0, offset = 0; id <= lastid;
id++, offset += sizeof(struct dqblk)) {
if (fread((char *)&dqbuf, sizeof(struct dqblk), 1, qfi) == 0)
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;
@ -485,27 +430,9 @@ update(char *fsname, char *quotafile, int type)
continue;
}
printchanges(fsname, type, &dqbuf, fup, id);
/*
* Reset time limit if have a soft limit and were
* previously under it, but are now over it.
*/
if (dqbuf.dqb_bsoftlimit && id != 0 &&
dqbuf.dqb_curblocks < dqbuf.dqb_bsoftlimit &&
fup->fu_curblocks >= dqbuf.dqb_bsoftlimit)
dqbuf.dqb_btime = 0;
if (dqbuf.dqb_isoftlimit && id != 0 &&
dqbuf.dqb_curinodes < dqbuf.dqb_isoftlimit &&
fup->fu_curinodes >= dqbuf.dqb_isoftlimit)
dqbuf.dqb_itime = 0;
dqbuf.dqb_curinodes = fup->fu_curinodes;
dqbuf.dqb_curblocks = fup->fu_curblocks;
if (fseeko(qfo, offset, SEEK_SET) < 0) {
warn("%s: seek failed", quotafile);
return(1);
}
fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
(void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
(caddr_t)&dqbuf);
(void) quota_write_usage(qf, &dqbuf, id);
fup->fu_curinodes = 0;
fup->fu_curblocks = 0;
}
@ -515,9 +442,8 @@ update(char *fsname, char *quotafile, int type)
* that are not currently recorded in the quota file. E.g.
* ids that are past the end of the current file.
*/
for (i = 0; i < FUHASH; i++) {
for (fup = fuhead[type][i]; fup != NULL; fup = fup->fu_next) {
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)
@ -525,26 +451,17 @@ update(char *fsname, char *quotafile, int type)
bzero(&dqbuf, sizeof(struct dqblk));
if (fup->fu_id > highid)
highid = fup->fu_id;
printchanges(fsname, type, &dqbuf, fup, id);
printchanges(fsname, type, &dqbuf, fup, fup->fu_id);
dqbuf.dqb_curinodes = fup->fu_curinodes;
dqbuf.dqb_curblocks = fup->fu_curblocks;
offset = (off_t)fup->fu_id * sizeof(struct dqblk);
if (fseeko(qfo, offset, SEEK_SET) < 0) {
warn("%s: seek failed", quotafile);
return(1);
}
fwrite((char *)&dqbuf, sizeof(struct dqblk), 1, qfo);
(void) quotactl(fsname, QCMD(Q_SETUSE, type), id,
(caddr_t)&dqbuf);
(void) quota_write_usage(qf, &dqbuf, fup->fu_id);
fup->fu_curinodes = 0;
fup->fu_curblocks = 0;
}
}
fclose(qfi);
fflush(qfo);
ftruncate(fileno(qfo),
(((off_t)highid + 1) * sizeof(struct dqblk)));
fclose(qfo);
if (highid < lastid)
truncate(quota_qfname(qf),
(((off_t)highid + 2) * sizeof(struct dqblk)));
return (0);
}
@ -575,55 +492,6 @@ getquotagid(void)
return (-1);
}
/*
* Check to see if a particular quota is to be enabled.
*/
int
hasquota(struct fstab *fs, int type, char **qfnamep)
{
char *opt;
char *cp;
struct statfs sfb;
static char initname, usrname[100], grpname[100];
static char buf[BUFSIZ];
if (!initname) {
(void)snprintf(usrname, sizeof(usrname), "%s%s",
qfextension[USRQUOTA], qfname);
(void)snprintf(grpname, sizeof(grpname), "%s%s",
qfextension[GRPQUOTA], qfname);
initname = 1;
}
strcpy(buf, fs->fs_mntops);
for (opt = strtok(buf, ","); opt; opt = strtok(NULL, ",")) {
if ((cp = index(opt, '=')) != NULL)
*cp++ = '\0';
if (type == USRQUOTA && strcmp(opt, usrname) == 0)
break;
if (type == GRPQUOTA && strcmp(opt, grpname) == 0)
break;
}
if (!opt)
return (0);
if (cp)
*qfnamep = cp;
else {
(void)snprintf(buf, sizeof(buf), "%s/%s.%s", fs->fs_file,
qfname, qfextension[type]);
*qfnamep = buf;
}
if (statfs(fs->fs_file, &sfb) != 0) {
warn("cannot statfs mount point %s", fs->fs_file);
return (0);
}
if (strcmp(fs->fs_file, sfb.f_mntonname)) {
warnx("%s not mounted for %s quotas", fs->fs_file,
type == USRQUOTA ? "user" : "group");
return (0);
}
return (1);
}
/*
* Routines to manage the file usage table.
*
@ -644,7 +512,7 @@ lookup(u_long id, int type)
* Add a new file usage id if it does not already exist.
*/
struct fileusage *
addid(u_long id, int type, char *name, char *fsname)
addid(u_long id, int type, char *name, const char *fsname)
{
struct fileusage *fup, **fhp;
int len;
@ -779,7 +647,7 @@ bread(ufs2_daddr_t bno, char *buf, long cnt)
* Display updated block and i-node counts.
*/
void
printchanges(char *fsname, int type, struct dqblk *dp,
printchanges(const char *fsname, int type, struct dqblk *dp,
struct fileusage *fup, u_long id)
{
if (!vflag)

View File

@ -32,12 +32,6 @@
* $FreeBSD$
*/
struct quotaname {
long flags;
char grpqfname[PATH_MAX];
char usrqfname[PATH_MAX];
};
extern int checkfstab();
extern int chkquota(char *, char *, struct quotaname *);
extern struct quotaname *needchk(struct fstab *);
extern char *blockcheck(char *);
extern int checkfstab(int, int);
extern int chkquota(char *, struct quotafile *, struct quotafile *);