DataMuseum.dk

Presents historical artifacts from the history of:

Commodore CBM-900

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about Commodore CBM-900

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - download

⟦9d5247768⟧ TextFile

    Length: 5109 (0x13f5)
    Types: TextFile
    Notes: UNIX file
    Names: »du.c«

Derivation

└─⟦f27320a65⟧ Bits:30001972 Commodore 900 hard disk image with partial source code
    └─⟦f4b8d8c84⟧ UNIX V7 Filesystem
        └─ ⟦this⟧ »cmd/du.c« 

TextFile

/*
 * Print a disc usage summary for
 * some directories.
 */

#include <stdio.h>
#include <types.h>
#include <dir.h>
#include <stat.h>
#include <errno.h>

#define	DIOSIZ	(BUFSIZ/8)	/* Size of directory i/o, until stacks grow */
#define	NLINK	500		/* Size of link table */
#define	NFNAME	1000		/* Size of filename */
#define	NRECUR	12		/* Depth of recursion < NFILE-3-2 */

int	aflag;			/* do files as well */
int	sflag;			/* only give total */
int	depth;			/* recursion depth */

struct	linktab	{
	ino_t	l_ino;
	dev_t	l_dev;
}	linktab[NLINK];
struct	linktab	*ltp;

char	fname[NFNAME];

char	toodeep[] = "directory structure too deep to traverse";

struct	stat	sb;

long	duentry();
long	dufork();
long	dusize();
char	*buildname();
void	duerr();
void	dumsg();
void	usage();
void	main();

void
main(argc, argv)
char *argv[];
{
	register int i;
	register char *ap;
	int estat;

	while (argc>1 && *argv[1]=='-') {
		for (ap = &argv[1][1]; *ap != '\0'; ap++)
			switch (*ap) {
			case 'a':
				aflag = 1;
				break;

			case 's':
				sflag = 1;
				break;

			default:
				usage();
			}
		argc--;
		argv++;
	}
	if (argc < 2)
		estat = du(".");
	else {
		estat = 0;
		for (i=1; i<argc; i++)
			estat |= du(argv[i]);
	}
	exit (estat);
}

/*
 * Print out disc usage summary
 */
du(name)
char *name;
{
	register char *ep, *cp;
	size_t size;
	int nondir;

	ltp = linktab;
	cp = name;
	ep = fname;
	while (*cp)
		*ep++ = *cp++;
	*ep = '\0';
	if (stat(name, &sb) < 0)
		duerr("%s: nonexistent", name);
	nondir = (sb.st_mode&S_IFMT) != S_IFDIR;
	size = duentry(ep, &sb);
	if (sflag || nondir)
		printf("%D\t%s\n", size, fname);
	return (0);
}

/*
 * Do a du on a single entry
 * The pointer is the end pointer
 * into the fname buffer.
 */
long
duentry(ep, sbp)
char *ep;
struct stat *sbp;
{
	extern int errno;
	size_t total, fsize;
	char iobuf[DIOSIZ];
	register char *np;
	register struct direct *dp;
	register int nb;
	int fd;
	int dirf;

	switch (sbp->st_mode & S_IFMT) {
	case S_IFREG:
		return (dusize(sbp));

	case S_IFDIR:
		total = dusize(sbp);
		if (++depth >= NRECUR) {
			depth = 0;
			return (dufork(ep, sbp));
		}
		if ((fd = open(fname, 0)) < 0) {
			dumsg("cannot open `%s'", fname);
			return (0);
		}
		while ((nb = read(fd, iobuf, DIOSIZ)) > 0)
			for (dp = iobuf; dp < &iobuf[nb]; dp++) {
				np = dp->d_name;
				if (*np++=='.'
				  && (*np=='\0' || (*np++=='.' && *np=='\0')))
					continue;
				if (dp->d_ino == 0)
					continue;
				if ((np = buildname(dp, ep)) == NULL)
					continue;
				if (stat(fname, &sb) < 0) {
					dumsg("stat failed on `%s'", fname);
					continue;
				}
				dirf = (sb.st_mode&S_IFMT)==S_IFDIR;
				fsize = duentry(np, sbp);
				if (aflag && !sflag && !dirf)
					prsize(fsize);
				total += fsize;
			}
		if (nb < 0)
			dumsg("%s: directory read error", fname);
		close(fd);
		*ep = '\0';
		if (!sflag)
			prsize(total);
		--depth;
		return (total);

	default:
		return (0);
	}
}

/*
 * Fork to do a du on recursive directory
 * structure that is too deep to fit into
 * user's open files.
 */
long
dufork(ep, sbp)
char *ep;
struct stat *sbp;
{
	register int i;
	register int pid;
	int pfd[2] = {0, 0};
	int status;
	long sz = 0;

	fflush(stdout);
	if (pipe(pfd)<0 || (pid = fork())<0) {
		if (pfd[0]) {
			close(pfd[0]);
			close(pfd[1]);
		}
		dumsg(toodeep);
		return (0);
	}
	if (pid) {
		close(pfd[1]);
		while (wait(&status) >= 0)
			;
		if (status || read(pfd[0], &sz, sizeof(long)) != sizeof(long))
			sz = 0;
		close(pfd[0]);
		return (sz);
	}
	for (i=3; i<_NFILE; i++)
		if (i != pfd[1])
			close(i);
	sz = duentry(ep, sbp);
	write(pfd[1], &sz, sizeof(long));
	close(pfd[1]);
	exit(0);
}

/*
 * Do a du on a single file.
 * (BUG: This must be made to account
 * for indirect blocks).
 */
long
dusize(sbp)
struct stat *sbp;
{
	if ((sbp->st_mode & S_IFMT) != S_IFDIR
	 && sbp->st_nlink > 1
	 && addlink(sbp->st_dev, sbp->st_ino))
		return (0);
	return ((sbp->st_size+BUFSIZ-1)/BUFSIZ);
}

/*
 * Print out a size line.
 */
prsize(blocks)
size_t blocks;
{
	printf("%D\t%s\n", blocks, fname);
}

/*
 * Build up the next entry
 * in the name.
 */
char *
buildname(dp, ep)
struct direct *dp;
register char *ep;
{
	register char *cp = dp->d_name;
	register unsigned n = DIRSIZ;

	if (ep+DIRSIZ+2 >= &fname[NFNAME]) {
		dumsg(toodeep);
		return (NULL);
	}
	if (ep[-1] != '/')
		*ep++ = '/';
	do {
		if (*cp == '\0')
			break;
		*ep++ = *cp++;
	} while (--n);
	*ep = '\0';
	return (ep);
}

/*
 * Add an entry to the table
 * of i-numbers with multiple links.
 * If there are too many multi-link files,
 * they will get counted twice.
 * Return 1 if already there.
 */
addlink(dev, ino)
register dev_t dev;
register ino_t ino;
{
	register struct linktab *lp;

	for (lp = linktab; lp<ltp; lp++)
		if (lp->l_ino==ino && lp->l_dev==dev)
			return (1);
	if (lp-linktab >= NLINK)
		return (0);
	lp->l_ino = ino;
	lp->l_dev = dev;
	ltp++;
	return (0);
}

void
usage()
{
	fprintf(stderr, "Usage: du [-s] [name ...]\n");
	exit(1);
}

/* VARARGS */
void
duerr(x)
{
	fprintf(stderr, "du: %r\n", &x);
	exit (1);
}

/* VARARGS */
void
dumsg(x)
{
	fprintf(stderr, "du: %r\n", &x);
}