[comp.os.minix] Here is du

ast@cs.vu.nl (Andy Tanenbaum) (06/07/87)

Here is a version of du - the disk usage program.  It was written by
Alistair G. Crooks and given to me for posting.  I have modified it
slightly in the process.

Andy Tanenbaum (ast@cs.vu.nl)

-----------------------------cut here -------------------

/* du - report on disk usage		Author: Alistair G. Crooks */

/*
 *	du.c		1.1	27/5/87		agc	Joypace Ltd.
 *
 *	Copyright 1987, Joypace Ltd., London UK. All rights reserved.
 *	This code may be freely distributed, provided that this notice
 *	remains attached.
 *
 *	du - a public domain interpretation of du(1).
 *
 *      Note that du does not report on inode blocks and other overhead,
 *      so the sizes it reports do not agree with those of df.
 */


#include "stdio.h"

#include "stat.h"
#include "blocksize.h"

char *prog;				/* program name */
char *optstr = "as";			/* -a and -s arguments */
int silent = 0;				/* silent mode */
int all = 0;				/* all directory entries mode */
char *startdir = ".";			/* starting from here */

#define	LINELEN 256

#define DIRNAMELEN 14
#define	LSTAT stat
typedef struct _dirstr {
  int	inum;
  char	d_name[DIRNAMELEN];
} DIR;
DIR dir;
#define ino_t unsigned short

typedef struct _alstr {
  int al_dev;
  ino_t	al_inum;
} ALREADY;

#define	MAXALREADY	50
ALREADY already[MAXALREADY];
int alc = 0;

/*
 *	myindex - stop the scanf bug
 */
char *myindex(s, c)
register char	*s;
register char	c;
{
  for (; *s; s++)
	if (*s == c)
		return(s);
  return(NULL);
}


/*
 *	getopt - parse the arguments given.
 *	retrieved from net.sources
 */
int	opterr = 1;
int	optind = 1;
int	optopt;
char	*optarg;

#define BADCH	(int)'?'
#define EMSG	""
#define TELL(s)	fputs(*nargv, stderr); fputs(s, stderr);\
	fputc(optopt, stderr); fputc('\n', stderr);\
	return(BADCH);

int getopt(nargc, nargv, ostr)
int	nargc;
char	**nargv;
char	*ostr;
{
  register char	*oli;
  static char	*place = EMSG;

  if (!*place) {
	if (optind >= nargc || *(place = nargv[optind]) != '-' || !*++place)
		return(EOF);
	if (*place == '-') {
		++optind;
		return(EOF);
	}
  }
  if ((optopt = (int)*place++) == (int)':' || !(oli = myindex(ostr, optopt))) {
	if (!*place)
		++optind;
	TELL(": illegal option -- ");
  }
  if (*++oli != ':') {
	optarg = NULL;
	if (!*place)
		++optind;
  } else {
	if (*place)
		optarg = place;
	else if (nargc <= ++optind) {
		place = EMSG;
		TELL(": option requires an argument -- ");
	} else
		optarg = nargv[optind];
	place = EMSG;
	++optind;
  }
  return(optopt);
}

/*
 *	makedname - make the direcory entry from the directory name,
 *	and the file name, placing it in out. If this would overflow,
 *	return 0, otherwise 1.
 */
int makedname(d, f, out, outlen)
char	*d;
char	*f;
char	*out;
int	outlen;
{
  char	*cp;

  if (strlen(d) + strlen(f) + 2 > outlen)
	return(0);
  for (cp = out ; *d ; *cp++ = *d++)
	;
  if (*(cp-1) != '/')
	*cp++ = '/';
  while (*f)
	*cp++ = *f++;
  *cp = '\0';
  return(1);
}

/*
 *	done - have we encountered (dev, inum) before? Returns 1 for yes,
 *	0 for no, and remembers (dev, inum).
 */
int done(dev, inum)
int	dev;
ino_t	inum;
{
  register ALREADY	*ap;
  register int		i;
  int			ret = 0;

  for (i = 0, ap = already ; i < alc ; ap++, i++)
	if (ap->al_dev == dev && ap->al_inum == inum) {
		ret = 1;
		break;
	}
  if (alc < MAXALREADY) {
	already[alc].al_dev = dev;
	already[alc++].al_inum = inum;
  }
  return(ret);
}

/*
 *	dodir - process the directory d. Return the long size (in blocks)
 *	of d and its descendants.
 */
long dodir(d)
char	*d;
{
  struct stat	s;
  long		total = 0L;
  char		dent[LINELEN];
  int		fd;
  
  if ((fd = open(d, 0)) < 0)
	return(0L);
  while (read(fd, &dir, sizeof(dir)) > 0) {
	if (strcmp(dir.d_name, ".") == 0 ||
	    strcmp(dir.d_name, "..") == 0)
		continue;
	if (dir.inum == 0)
		continue;
	if (!makedname(d, dir.d_name, dent, sizeof(dent)))
		continue;
	if (LSTAT(dent, &s) < 0)
		continue;
	if (s.st_nlink > 1 && done(s.st_dev, s.st_ino))
		continue;
	if ((s.st_mode & S_IFMT) == S_IFDIR)
		total += dodir(dent);
	switch(s.st_mode & S_IFMT) {
	case S_IFREG:
	case S_IFDIR:
		total += (s.st_size + BLOCK_SIZE) / BLOCK_SIZE;
		break;
	}
	if (all && (s.st_mode & S_IFMT) != S_IFDIR)
		printf("%D\t%s\n", (s.st_size + BLOCK_SIZE) / BLOCK_SIZE, dent);
  }
  close(fd);
  if (!silent)
	printf("%D\t%s\n", total, d);
  return(total);
}

/*
 *	OK, here goes...
 */
main(argc, argv)
int	argc;
char	**argv;
{
  long	tot;
  int	c;

  prog = argv[0];
  while ((c = getopt(argc, argv, optstr)) != EOF)
	switch(c) {
	case 'a' :
		all = 1;
		break;
	case 's' :
		silent = 1;
		break;
	default :
		fprintf(stderr, "Usage: %s [-a] [-s] [startdir]\n", prog);
		exit(1);
	}
  if (optind < argc)
	startdir = argv[optind];
  tot = dodir(startdir);
  if (silent)
	printf("%D\t%s\n", tot, startdir);
  exit(0);
}

go@orstcs.UUCP (06/13/87)

Not to start a war (this belongs in *.legal anyway...)

Regarding the recent "du" posting:

"... All rights reserved ..."

"... public domain ..."

"Public domain" means "no rights reserved."  I do wish folks wouldn't 
try to confuse me.  This is just a comment -- no ill will intended, really.
Thanks for the program -- I was hoping one of these would come along.

Gary Oliver
...!hplabs!hp-pcd!orstcs!squint!go