[comp.os.minix] Kees Bot's df.c for large disks

ast@cs.vu.nl (Andy Tanenbaum) (10/25/89)

Here is df.c for larger disks.  Since my own disk is 20M, it is hard to
create 32M and larger partitions.  Could somebody please give this a test.

Andy Tanenbaum (ast@cs.vu.nl)


/* df - disk free block printout	Author: Andy Tanenbaum */

#include <minix/const.h>
#include <minix/type.h>
#include <fs/const.h>
#include <fs/type.h>
#include <fs/super.h>

#define block_nr long		/* Allow big devices even if FS doesn't */

#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdio.h>

extern int errno;

char *mtab = "/etc/mtab";

#define REPORT 0
#define SILENT 1


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

  sync();			/* have to make sure disk is up-to-date */
  fprintf(stdout,"\nDevice     Inodes  Inodes  Inodes       Blocks  Blocks  Blocks    ");
  if (argc == 1) 
	fprintf(stdout, "Mounted on\n");
  else
	fprintf(stdout, "\n");

  fprintf(stdout,"           total   used    free         total   used    free\n");
  fprintf(stdout,"           -----   -----   -----        -----   -----   -----\n");

  if (argc == 1) defaults();

  for (i = 1; i < argc; i++)
	df(argv[i], "", SILENT);
  exit(0);
}


#define percent(num, tot)  ((int) ((100L * (num) + ((tot) - 1)) / (tot)))

df(name, mnton, silent)
char *name, *mnton;
int silent;
{
  register int fd;
  inode_nr i_count, z_count;
  block_nr totblocks, busyblocks;
  int i, j;
  char buf[BLOCK_SIZE], *s0;
  struct super_block super, *sp;

  if ((fd = open(name, 0)) < 0) {
	if (!silent) {
		int e = errno;

		fprintf(stderr, "df: ");
		errno = e;
		perror(name);
	}
	return;
  }
  lseek(fd, (long) BLOCK_SIZE, 0);	/* skip boot block */
  if (read(fd, &super, SUPER_SIZE) != SUPER_SIZE) {
	fprintf(stderr, "df: Can't read super block of %s\n", name);
	close(fd);
	return;
  }
  lseek(fd, (long) BLOCK_SIZE * 2L, 0);	/* skip rest of super block */
  sp = &super;
  if (sp->s_magic != SUPER_MAGIC) {
	fprintf(stderr, "df: %s: Not a valid file system\n", name);
	close(fd);
	return;
  }
  i_count = bit_count(sp->s_imap_blocks, sp->s_ninodes + 1, fd);
  if (i_count == -1) {
	fprintf(stderr, "df: Can't find bit maps of %s\n", name);
	close(fd);
	return;
  }
  i_count--;			/* There is no inode 0. */

  z_count = bit_count(sp->s_zmap_blocks, sp->s_nzones, fd);
  if (z_count == -1) {
	fprintf(stderr, "df: Can't find bit maps of %s\n", name);
	close(fd);
	return;
  }
  totblocks = (block_nr) sp->s_nzones << sp->s_log_zone_size;
  busyblocks = (block_nr) z_count << sp->s_log_zone_size;

  /* Print results. */
  fprintf(stdout, "%s", name);
  j = 10 - strlen(name);
  while (j > 0) {
	fprintf(stdout, " ");
	j--;
  }

  fprintf(stdout, " %5u   %5u   %5u      %7ld %7ld %7ld     %s\n",
	 sp->s_ninodes,		  /* total inodes */
	 i_count,		  /* inodes used */
	 sp->s_ninodes - i_count, /* inodes free */

	 totblocks,		  /* total blocks */
	 busyblocks,		  /* blocks used */
	 totblocks - busyblocks,  /* blocsk free */

	 strcmp(mnton, "device")  == 0 ? "(root dev)" : mnton

	);
  close(fd);
}

bit_count(blocks, bits, fd)
int blocks;
int bits;
int fd;
{
  register int i, b;
  int busy, count, w;
  int *wptr, *wlim;
  int buf[BLOCK_SIZE / sizeof(int)];

  /* Loop on blocks, reading one at a time and counting bits. */
  busy = 0;
  count = 0;
  for (i = 0; i < blocks; i++) {
	if (read(fd, buf, BLOCK_SIZE) != BLOCK_SIZE) return(-1);

	wptr = &buf[0];
	wlim = &buf[BLOCK_SIZE / sizeof(int)];

	/* Loop on the words of a block */
	while (wptr != wlim) {
		w = *wptr++;

		/* Loop on the bits of a word. */
		for (b = 0; b < 8 * sizeof(int); b++) {
			if ((w >> b) & 1) busy++;
			if (++count == bits) return (busy);
		}
	}
  }
  return(0);
}


char mtabbuf[1024];
int mtabcnt;

getname(d, m)
char **d, **m;
{
  int c;
  static char *mp = mtabbuf;

  *d = mp;
  *m = "";

  do {
	if (--mtabcnt < 0) exit(0);
	c = *mp++;
	if (c == ' ') {
		mp[-1] = 0;
		*m = mp;
	}
  } while (c != '\n');
  mp[-1] = 0;
}

defaults()
{
/* Use the root file system and all mounted file systems. */

  char *dev, *dir;

  close(0);
  if (open(mtab, 0) < 0 || (mtabcnt = read(0, mtabbuf, sizeof(mtabbuf)))<= 0) {
	fprintf(stderr, "df: cannot read %s\n", mtab);
	exit(1);
  }

  /* Read /etc/mtab and iterate on the lines. */
  while (1) {
	getname(&dev, &dir);	/* getname exits upon hitting EOF */
	df(dev, dir, REPORT);
  }

}


static int fd, w, left;
static char fill;

static void wr(a, n)
char *a;
int n;
{
  if (left && n > 0) write(fd, a, n);

  while (w > n) {
	write(fd, &fill, 1);
	--w;
  }

  if (!left && n > 0) write(fd, a, n);
}

static void pr_n(neg, n)
int neg;
unsigned long n;
{
  char a[3 * sizeof(n) + 1], *pa = a + sizeof(a);

  do
	*--pa = '0' + n % 10;
  while ((n /= 10) != 0);

  if (neg) *--pa = '-';

  wr(pa, a + sizeof(a) - pa);
}

static void pr_i(i)
long i;
{
  int neg = 0;

  if (i < 0) {
	neg = 1;
	i = -i;
  }
  pr_n(neg, (unsigned long) i);
}