V9/cmd/df.c

Compare this file to the similar file:
Show the results in this format:

static	char *sccsid = "@(#)df.c	4.6 (Berkeley) 7/8/81";
#include <stdio.h>
#include <fstab.h>
#include <sys/param.h>
#include <sys/filsys.h>
#include <sys/fblk.h>
#include <sys/stat.h>
/*
 * df
 */

#define NFS	32	/* Max number of filesystems */

#define	KBYTE	1024

struct mtab {
	char path[FSNMLG];
	char spec[FSNMLG];
} mtab[NFS];
struct stat stb;
int dev;
#define	L10BS	6
#define	L10IS	5
#define PCTFW	3
int	DEVNMLG;		/* length of longest device name */
int	DIRNMLG;		/* length of longest mount point name */

char *mpath();

daddr_t	blkno	= 1;

int	lflag;
int	iflag;

struct	filsys sblock;

int	fi;
daddr_t	alloc();

main(argc, argv)
register int argc;
register char **argv;
{
	register int i;
	register int r = 0;

	while (argc > 1 && argv[1][0]=='-') {
		switch(argv[1][1]) {

		case 'l':
			lflag++;
			break;

		case 'i':
			iflag++;
			break;

		default:
			fprintf(stderr, "usage: df [-i] [-l] [filsys...]\n");
			exit(0);
		}
		argc--, argv++;
	}

	if ((i=open("/etc/mtab", 0)) >= 0) {
		r = read(i, mtab, sizeof mtab);	/* Probably returns short */
		(void) close(i);
		r /= sizeof mtab[0];
	}
	devlen(r);	/* reads in all of /etc/fstab, too */
	printf("%-*.*s %-*.*s %*.*s %*.*s %*.*s",
		DIRNMLG, DIRNMLG, "dir",
		DEVNMLG, DEVNMLG, "dev",
		L10BS, L10BS, "kbytes",
		L10BS, L10BS, "used",
		L10BS, L10BS, "free");
	if (lflag)
		printf(" %*.*s", L10BS, L10BS, "hardway");
	printf(" %*.*s", PCTFW + 1, PCTFW + 1, "%use");
	if (iflag)
		printf(" %*.*s %*.*s %*.*s",
			L10IS, L10IS, "iused",
			L10IS, L10IS, "ifree",
			PCTFW + 1, PCTFW + 1, "%ino");
	putchar('\n');
	if(argc <= 1) {
		for (i = 0; i < NFS && mtab[i].spec[0]; ++i)
			dfree(mtab[i].path);
		return (0);
	}

	for(i=1; i<argc; i++)
		dfree(argv[i]);
	return (0);
}

dfree(file)
char *file;
{
	register daddr_t i;
	register char	*mp;
	long	blocks;
	long	free;
	long	used;
	long	hardway;
	struct	stat stbuf;
	static char specbuf[FSNMLG + sizeof "/dev/"] = "/dev/";

	if(stat(file, &stbuf) == 0 && (stbuf.st_mode&S_IFMT) == S_IFDIR)
	{
		struct stat mstbuf;

		for (i = 0; i < NFS && mtab[i].spec[0]; ++i)
		{
			strcpy(&specbuf[5], mtab[i].spec);
			if(!stat(specbuf, &mstbuf) && mstbuf.st_rdev == stbuf.st_dev)
			{
				file = specbuf;
				break;
			}
		}
		if (i == NFS || mtab[i].spec[0] == '\0')
		{
			fprintf(stderr, "%s mounted on unknown device\n", file);
			return;
		}
	}
	else
	if (strncmp("/dev/", file, sizeof "/dev/" - 1) != 0)
		strcpy(&specbuf[5], file), file = specbuf;
	fi = open(file, 0);
	if(fi < 0)
	{
		fprintf(stderr,"cannot open %s\n", file);
		return;
	}
	fstat(fi, &stb);
	dev = stb.st_rdev;
	if (lflag)
		sync();
	bread(1L, (char *)&sblock, sizeof(sblock));
	blocks = (long) sblock.s_fsize - (long)sblock.s_isize;
	free = sblock.s_tfree;
	used = blocks - free;
	blocks *= BSIZE(dev) / KBYTE;
	free *= BSIZE(dev) / KBYTE;
	used *= BSIZE(dev) / KBYTE;
	printf("%-*.*s %-*.*s %*ld %*ld %*ld",
		DIRNMLG, DIRNMLG, mp = mpath(file),
		DEVNMLG, DEVNMLG, file + sizeof "/dev",
		L10BS, blocks, L10BS, used, L10BS, free);

	if (lflag) {
		hardway = 0;
		if(BITFS(dev))
			hardway = alloc();
		else
			while(alloc())
				hardway++;
		hardway *= BSIZE(dev) / KBYTE;
		printf(" %*ld", L10BS, free = hardway);
	}
	printf(" %*.0f%%", 
		PCTFW, blocks == 0 ?
		0.0 : (double) used / (double) blocks * 100.0);
	if (iflag) {
		int inodes = (sblock.s_isize - 2) * INOPB(dev);
		used = inodes - sblock.s_tinode;
		printf(" %*ld %*ld %*.0f%%",
			L10IS, used,
			L10IS, sblock.s_tinode, 
			PCTFW, inodes == 0 ?
			0.0 : (double) used / (double) inodes * 100.0);
	}
	printf("\n");
	close(fi);
}

daddr_t
alloc()
{
	int i, j, n;
	daddr_t b;
	struct fblk buf;

	if(!BITFS(dev)) {
		i = --sblock.s_nfree;
		if(i<0 || i>=NICFREE) {
			printf("bad free count, b=%D\n", blkno);
			return(0);
		}
		b = sblock.s_free[i];
		if(b == 0)
			return(0);
		if(b<sblock.s_isize || b>=sblock.s_fsize) {
			printf("bad free block (%D)\n", b);
			return(0);
		}
		if(sblock.s_nfree <= 0) {
			bread(b, (char *)&buf, sizeof(buf));
			blkno = b;
			sblock.s_nfree = buf.df_nfree;
			for(i=0; i<NICFREE; i++)
				sblock.s_free[i] = buf.df_free[i];
		}
		return(b);
	}
	n = 0;
	for(i = 0; i < BITMAP; i++)
		for(j = 0; j < 32; j++)		/* 32: bits per int */
			if(sblock.s_bfree[i] & (1 << j))
				n++;
	return(n);
}

bread(bno, buf, cnt)
daddr_t bno;
char *buf;
{
	register int n;
	extern errno;

	lseek(fi, bno<<BSHIFT(dev), 0);
	if((n=read(fi, buf, cnt)) != cnt) {
		printf("\nread error bno = %ld\n", bno);
		printf("count = %d; errno = %d\n", n, errno);
		exit(0);
	}
}

/*
 * Given a name like /dev/rrp0h, returns the mounted path, like /usr.
 */
char *mpath(file)
char *file;
{
	register int i;

	for (i=0; i<NFS; i++)
		if (eq(file, mtab[i].spec))
			return mtab[i].path;
	return "";
}

eq(f1, f2)
char *f1, *f2;
{
	if (strncmp(f1, "/dev/", 5) == 0)
		f1 += 5;
	if (strncmp(f2, "/dev/", 5) == 0)
		f2 += 5;
	if (strcmp(f1, f2) == 0)
		return 1;
	if (*f1 == 'r' && strcmp(f1+1, f2) == 0)
		return 1;
	if (*f2 == 'r' && strcmp(f1, f2+1) == 0)
		return 1;
	if (*f1 == 'r' && *f2 == 'r' && strcmp(f1+1, f2+1) == 0)
		return 1;
	return 0;
}

mtabcmp(mp0, mp1)
struct mtab *mp0;
struct mtab *mp1;
{
	/*
	 * don't let empty mtab slots sort to the front
	 * as dfree will break
	 * the wrong way to fix it: the whole algorithm is wrong
	 */
	if (mp0->path[0] == 0)
		return (1);
	if (mp1->path[0] == 0)
		return (-1);
	return (strncmp(mp0->path, mp1->path, sizeof (mp0->path)));
}

devlen(r)
register int r;
{
	register struct	fstab	*fsp;
	register int		i;

	DEVNMLG = 0;
	DIRNMLG = 0;
	if (setfsent() == 0)
		perror(FSTAB), exit(1);
	while( (fsp = getfsent()) != 0){
		if (  (strcmp(fsp->fs_type, FSTAB_RW) != 0)
			&&(strcmp(fsp->fs_type, FSTAB_RO) != 0) )
			continue;
		for (i = 0; mtab[i].spec[0]; ++i)
		{
			if (strncmp(mtab[i].spec, fsp->fs_spec + 5,
				sizeof fsp->fs_spec - 5) == 0)
				break;
		}
		if (i == r && i < NFS)
		{
			strncpy(mtab[r].spec, fsp->fs_spec + 5,
				sizeof fsp->fs_spec - 5);
			strncpy(mtab[r].path, fsp->fs_file, sizeof fsp->fs_file);
			++r;
		}
		if (DEVNMLG < (i = strlen(fsp->fs_spec)))
			DEVNMLG = i;
		if (DIRNMLG < (i = strlen(fsp->fs_file)))
			DIRNMLG = i;
	}
	endfsent();
	DEVNMLG -= sizeof "/dev";
	if (DEVNMLG < sizeof "dev" - 1)
		DEVNMLG = sizeof "dev" - 1;
	if (DIRNMLG < sizeof "dir" - 1)
		DIRNMLG = sizeof "dir" - 1;
	qsort(&mtab[0], r, sizeof mtab[0], mtabcmp);
}