#include <sys/param.h>
#include <sys/quota.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#if REV_ENDIAN_FS
#import "ufs_byte_order.h"
#endif
#include "quotacheck.h"
union {
struct fs sblk;
char dummy[MAXBSIZE];
} un;
#define sblock un.sblk
long dev_bsize;
long maxino;
int fi;
#if REV_ENDIAN_FS
int rev_endian=0;
#endif
void bread(daddr_t, char *, long);
void freeinodebuf(void);
struct dinode *
getnextinode(ino_t);
void resetinodebuf(void);
int
chkquota_ufs(fsname, mntpt, qnp)
char *fsname, *mntpt;
register struct quotaname *qnp;
{
register struct fileusage *fup;
register struct dinode *dp;
int cg, i, mode, errs = 0;
ino_t ino;
if ((fi = open(fsname, O_RDONLY, 0)) < 0) {
perror(fsname);
return (1);
}
sync();
dev_bsize = 1;
bread(SBOFF, (char *)&sblock, (long)SBSIZE);
if (sblock.fs_magic != FS_MAGIC) {
#if REV_ENDIAN_FS
byte_swap_sbin(&sblock);
if (sblock.fs_magic != FS_MAGIC) {
#endif
(void)printf("%s: superblock has bad magic number, skipped",
fsname);
(void)close(fi);
return (1);
#if REV_ENDIAN_FS
} else {
if(vflag)
(void)printf("Reverse Byte order Filesystem Detected\n");
rev_endian=1;
}
#endif
}
#if REV_ENDIAN_FS
else rev_endian=0;
#endif
dev_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
maxino = sblock.fs_ncg * sblock.fs_ipg;
resetinodebuf();
for (ino = 0, cg = 0; cg < sblock.fs_ncg; cg++) {
for (i = 0; i < sblock.fs_ipg; i++, ino++) {
if (ino < ROOTINO)
continue;
if ((dp = getnextinode(ino)) == NULL)
continue;
if ((mode = dp->di_mode & IFMT) == 0)
continue;
if (qnp->flags & HASGRP) {
fup = addid((u_long)dp->di_gid, GRPQUOTA);
fup->fu_curinodes++;
if (mode == IFREG || mode == IFDIR ||
mode == IFLNK)
fup->fu_curbytes +=
dbtob((u_int64_t)dp->di_blocks, dev_bsize);
}
if (qnp->flags & HASUSR) {
fup = addid((u_long)dp->di_uid, USRQUOTA);
fup->fu_curinodes++;
if (mode == IFREG || mode == IFDIR ||
mode == IFLNK)
fup->fu_curbytes +=
dbtob((u_int64_t)dp->di_blocks, dev_bsize);
}
}
}
freeinodebuf();
if (qnp->flags & HASUSR)
errs += update(mntpt, qnp->usrqfname, USRQUOTA);
if (qnp->flags & HASGRP)
errs += update(mntpt, qnp->grpqfname, GRPQUOTA);
close(fi);
return (errs);
}
ino_t nextino, lastinum;
long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
struct dinode *inodebuf;
#define INOBUFSIZE 56*1024
struct dinode *
getnextinode(inumber)
ino_t inumber;
{
long size;
daddr_t dblk;
static struct dinode *dp;
if (inumber != nextino++ || inumber > maxino)
err(1, "bad inode number %d to nextinode", inumber);
if (inumber >= lastinum) {
readcnt++;
dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum));
if (readcnt % readpercg == 0) {
size = partialsize;
lastinum += partialcnt;
} else {
size = inobufsize;
lastinum += fullcnt;
}
bread(dblk, (char *)inodebuf, size);
#if REV_ENDIAN_FS
if (rev_endian)
byte_swap_dinodecount(inodebuf, size, 0);
#endif
dp = inodebuf;
}
return (dp++);
}
void
resetinodebuf()
{
nextino = 0;
lastinum = 0;
readcnt = 0;
inobufsize = blkroundup(&sblock, INOBUFSIZE);
fullcnt = inobufsize / sizeof(struct dinode);
readpercg = sblock.fs_ipg / fullcnt;
partialcnt = sblock.fs_ipg % fullcnt;
partialsize = partialcnt * sizeof(struct dinode);
if (partialcnt != 0) {
readpercg++;
} else {
partialcnt = fullcnt;
partialsize = inobufsize;
}
if (inodebuf == NULL &&
(inodebuf = malloc((u_int)inobufsize)) == NULL)
err(1, "%s", strerror(errno));
while (nextino < ROOTINO)
getnextinode(nextino);
}
void
freeinodebuf()
{
if (inodebuf != NULL)
free(inodebuf);
inodebuf = NULL;
}
void
bread(bno, buf, cnt)
daddr_t bno;
char *buf;
long cnt;
{
if (lseek(fi, (off_t)bno * dev_bsize, SEEK_SET) < 0 ||
read(fi, buf, cnt) != cnt)
err(1, "block %ld", bno);
}