|
|
DataMuseum.dkPresents historical artifacts from the history of: Commodore CBM-900 |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about Commodore CBM-900 Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - download
Length: 9400 (0x24b8)
Types: TextFile
Notes: UNIX file
Names: »quot.c«
└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
└─⟦f4b8d8c84⟧ UNIX Filesystem
└─⟦this⟧ »cmd/quot.c«
/*
* Produce various information about
* filesystem space usage and owners.
* The options of this command seem a
* little too disjoint in their functionality.
*/
#include <stdio.h>
#include <ino.h>
#include <filsys.h>
#include <canon.h>
#include <pwd.h>
#include <ctype.h>
#define NHASH 64 /* Hash names table (power of 2) */
#define NIREAD (20*BUFSIZ) /* Inode bytes per read */
#define NCUM 2047 /* Number of different size entries */
#define BADSIZE (-1) /* not valid - for hash synonym checking */
#define BADUID (-1) /* not valid - for hash synonyms */
/*
* Hash table of names
*/
typedef struct NAME {
struct NAME *n_next;
unsigned short n_uid;
char n_name[];
} NAME;
/*
* Entry of hash table of
* -f and ordinary options.
*/
typedef struct FENTRY {
unsigned short f_uid;
long f_nfiles;
long f_nblocks;
} FENTRY;
/*
* Entry of hash table for
* -c (cumulative sizes)
*/
typedef struct CENTRY {
unsigned long c_nblocks; /* Size of file in blocks */
long c_nfiles; /* #files of that size */
} CENTRY;
NAME *names[NHASH];
FENTRY *fentries; /* File count and size entries */
FENTRY *efp; /* Pointer to end of `fentries' */
CENTRY *centries; /* Cumulative size entries */
CENTRY *ecp; /* Pointer to end of `centries' */
CENTRY *lastcep; /* Last for sorting */
char ibuf[NIREAD]; /* I-node read buffer */
char incopt[] = "incompatible options given";
int cflag; /* cumulative sizes list */
int fflag; /* #files as well as space */
int nflag; /* List of files and owners (via ncheck) */
int tflag; /* Print a total */
int nuids; /* Number of uids found in /etc/passwd */
ino_t readino; /* Last i-number read from input (`-n') */
char *readfile; /* Last filename read as above */
char *line; /* Line that is read in */
char *username();
char *alloc();
FENTRY *getfentry();
CENTRY *getcentry();
int fcomp();
int ccomp();
main(argc, argv)
int argc;
register char *argv[];
{
register char *ap;
register int es = 0;
register int mflag;
register int fd;
while (argc>1 && *argv[1]=='-') {
for (ap = &argv[1][1]; *ap!='\0'; ap++)
switch (*ap) {
case 'n':
nflag++;
if (cflag || fflag)
cerr(incopt);
break;
case 'c':
cflag++;
if (nflag || fflag)
cerr(incopt);
break;
case 'f':
fflag++;
if (nflag || cflag)
cerr(incopt);
break;
case 't':
tflag++;
if (nflag)
cerr(incopt);
break;
default:
usage();
}
argv++;
argc--;
}
argv++;
if (argc < 2)
usage();
mflag = 0;
if (argv[0]!=NULL && argv[1]!=NULL)
mflag++;
for ( ; *argv!=NULL; argv++) {
if ((fd = open(*argv, 0)) < 0) {
cwarn("cannot open `%s'", *argv);
continue;
}
if (mflag)
fprintf(stderr, "%s:\n", *argv);
quotinit();
es |= quot(fd, *argv);
quotterm();
close(fd);
}
exit(es);
}
/*
* Initialise things for `quot' for
* each filesystem pass.
*/
quotinit()
{
if (!cflag && nuids==0) {
readnames();
nuids *= 2;
}
if (!nflag && !cflag) {
register FENTRY *fep;
fentries = (FENTRY *)alloc(nuids*sizeof (FENTRY));
efp = &fentries[nuids];
for (fep = fentries; fep < efp; fep++)
fep->f_uid = BADUID;
} else if (cflag) {
register CENTRY *cep;
centries = (CENTRY *)alloc(NCUM*sizeof(CENTRY));
lastcep = centries;
ecp = ¢ries[NCUM];
for (cep = centries; cep < ecp; cep++)
cep->c_nblocks = BADSIZE;
} else {
line = alloc(1000);
readino = 0;
}
}
/*
* Routine run between filesystems
* to clean up allocated storage.
* Also may print out tables.
*/
quotterm()
{
if (fentries != NULL) {
register FENTRY *fep;
long totblocks = 0;
long totfiles = 0;
qsort((char *)fentries, nuids, sizeof(FENTRY), fcomp);
for (fep=fentries; fep < efp; fep++) {
if (fep->f_uid == BADUID)
break;
if (tflag) {
totblocks += fep->f_nblocks;
totfiles += fep->f_nfiles;
}
if (fflag)
printf("%8D ", fep->f_nfiles);
printf("%8D %s\n", fep->f_nblocks,
username(fep->f_uid));
}
if (tflag) {
if (fflag)
printf("%8D ", totfiles);
printf("%8D Total\n", totblocks);
}
free((char *)fentries);
fentries = NULL;
} else if (centries != NULL) {
register CENTRY *cep;
long cumblocks = 0;
qsort((char *)centries, lastcep-centries, sizeof(CENTRY), ccomp);
for (cep = centries; cep < lastcep; cep++) {
if (cep->c_nblocks == BADSIZE)
break;
cumblocks += cep->c_nblocks*cep->c_nfiles;
printf("%8D %8D %10D\n", cep->c_nblocks,
cep->c_nfiles, cumblocks);
}
free((char *)centries);
centries = NULL;
}
}
/*
* Called for each filesystem that is read.
*/
quot(fsfd, fs)
int fsfd;
char *fs;
{
register ino_t maxino;
register ino_t inum;
{
register struct filsys *sbp;
lseek(fsfd, (size_t)(SUPERI*BSIZE), 0);
if (read(fsfd, ibuf, BSIZE) != BSIZE)
cerr("%s: bad filesystem format", fs);
sbp = ibuf;
canshort(sbp->s_isize);
candaddr(sbp->s_fsize);
if (sbp->s_isize > sbp->s_fsize) {
cwarn("%s: ridiculous fsize/isize", fs);
return (1);
}
maxino = (sbp->s_isize-INODEI) * INOPB;
}
lseek(fsfd, (size_t)(INODEI*BSIZE), 0);
inum = 0;
for (;;) {
register struct dinode *ip;
if (read(fsfd, ibuf, sizeof ibuf) <= 0) {
cwarn("%s: i-node read error", fs);
return (1);
}
for (ip=ibuf; ip < &ibuf[NIREAD]; ip++) {
if (inum++ >= maxino)
break;
canshort(ip->di_uid);
canshort(ip->di_mode);
cansize(ip->di_size);
if (ilook(ip, inum))
return (0);
}
if (inum > maxino)
break;
}
return (0);
}
/*
* Routine that looks at every I-node
* that we find.
* Return 1 for premature end.
*/
ilook(ip, ino)
register struct dinode *ip;
register ino_t ino;
{
if (ip->di_mode == 0)
return (0);
if (nflag) {
register char *lp;
while (ino > readino) {
if (gets(line) == NULL)
return (1);
for (lp=line; *lp==' ' || *lp=='\t'; lp++)
;
if (!isdigit(*lp))
continue;
readino = atoi(lp);
while (isdigit(*lp))
lp++;
while (*lp==' ' || *lp=='\t')
lp++;
readfile = lp;
}
if (readino == ino)
printf("%-16s %s\n", username(ip->di_uid), readfile);
} else if (cflag) {
register CENTRY *cep;
long size;
size = (ip->di_size+BSIZE-1)/BSIZE;
cep = getcentry(size);
cep->c_nfiles++;
} else {
register FENTRY *fep;
fep = getfentry(ip->di_uid);
fep->f_nfiles++;
switch (ip->di_mode & IFMT) {
case IFREG:
case IFDIR:
fep->f_nblocks += (ip->di_size+BSIZE-1)/BSIZE;
break;
}
}
return (0);
}
/*
* Using hashing from a large pool,
* return a pointer to where the FENTRY
* for that uid was put or created.
* The table has to be contiguous for sorting.
*/
FENTRY *
getfentry(uid)
register short unsigned uid;
{
register FENTRY *fep;
fep = &fentries[(uid<<1)%nuids];
for (;;) {
if (fep >= efp)
fep = fentries;
if (fep->f_uid == uid)
return (fep);
if (fep->f_uid == BADUID) {
fep->f_uid = uid;
return (fep);
}
fep++;
}
}
/*
* Return a CENTRY for a particular file size.
* This is hashed much like the FENTRY code
* above.
*/
CENTRY *
getcentry(nb)
long nb;
{
register CENTRY *cep;
cep = ¢ries[((unsigned)nb<<1)%NCUM];
for (;;) {
if (cep >= ecp)
cep = centries;
if (cep->c_nblocks == nb)
return (cep);
if (cep->c_nblocks == BADSIZE) {
cep->c_nblocks = nb;
if (cep > lastcep)
lastcep = cep+1;
return (cep);
}
cep++;
}
}
/*
* Read all of the names from `/etc/passwd'
* and build up a hash table.
* Duplicates are discarded.
*/
readnames()
{
register NAME *np;
register unsigned short hash;
register struct passwd *pwp;
while ((pwp = getpwent()) != NULL) {
hash = pwp->pw_uid%NHASH;
for (np = names[hash]; np != NULL; np = np->n_next)
if (np->n_uid == pwp->pw_uid)
break;
if (np == NULL) {
nuids++;
np = (NAME*)alloc(sizeof(NAME)+strlen(pwp->pw_name)+1);
strcpy(np->n_name, pwp->pw_name);
np->n_uid = pwp->pw_uid;
np->n_next = names[hash];
names[hash] = np;
}
}
endpwent();
}
/*
* Return user name for a particular number.
* Names that are not located are given the string
* representation of the number.
*/
char *
username(uid)
unsigned short uid;
{
register NAME *np;
static char buf[12];
for (np = names[uid%NHASH]; np != NULL; np = np->n_next)
if (np->n_uid == uid)
return (np->n_name);
return (sprintf(buf, "%u", uid));
}
/*
* Comparison routine for no options
* and `-f'. Sort by # blocks, then
* # files.
*/
fcomp(fep1, fep2)
register FENTRY *fep1, *fep2;
{
if (fep1->f_nblocks < fep2->f_nblocks)
return (1);
if (fep1->f_nblocks > fep2->f_nblocks)
return (-1);
if (fep1->f_nfiles < fep2->f_nfiles)
return (1);
if (fep1->f_nfiles > fep2->f_nfiles)
return (-1);
return (0);
}
/*
* Sort comparison routine for the
* `-c' (cumulative size table)
* option.
*/
ccomp(cep1, cep2)
register CENTRY *cep1, *cep2;
{
if (cep1->c_nblocks < cep2->c_nblocks)
return (-1);
if (cep1->c_nblocks > cep2->c_nblocks)
return (1);
return (0);
}
/*
* Call allocator and check for errors.
*/
char *
alloc(nb)
register unsigned nb;
{
register char *ap;
if ((ap = calloc(nb, 1)) == NULL)
cerr("out of memory");
return (ap);
}
/*
* Errors and usage message.
*/
/* VARARGS */
cerr(x)
{
fprintf(stderr, "quot: %r\n", &x);
exit(1);
}
cwarn(x)
{
fprintf(stderr, "quot: %r\n", &x);
exit(1);
}
usage()
{
fprintf(stderr, "Usage: quot [-n] [-c] [-ft] filesystem [ ... ]\n");
exit(1);
}