255 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			255 lines
		
	
	
		
			5.9 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
/* du - report on disk usage		Author: Alistair G. Crooks */
 | 
						|
 | 
						|
/*
 | 
						|
 *	du.c		1.1	27/5/87		agc	Joypace Ltd.
 | 
						|
 *			1.2	24 Mar 89	nick@nswitgould.oz
 | 
						|
 *			1.3	31 Mar 89	nick@nswitgould.oz
 | 
						|
 *			1.4	22 Feb 90	meulenbr@cst.prl.philips.nl
 | 
						|
 *			1.5	09 Jul 91	hp@vmars.tuwien.ac.at
 | 
						|
 *			1.6	01 Oct 92	kjb@cs.vu.nl
 | 
						|
 *			1.7	04 Jan 93	bde
 | 
						|
 *			1.8	19 Sep 94	kjb
 | 
						|
 *			1.9	28 Oct 99	kjb
 | 
						|
 *
 | 
						|
 *	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).
 | 
						|
 *
 | 
						|
 *  1.2: 	Fixed bug involving 14 character long filenames
 | 
						|
 *  1.3:	Add [-l levels] option to restrict printing.
 | 
						|
 *  1.4:	Added processing of multiple arguments
 | 
						|
 *  1.5:	Fixed processing of multiple arguments. General cleanup.
 | 
						|
 *  1.6:	Use readdir
 | 
						|
 *  1.7:	Merged 1.5 and 1.6.
 | 
						|
 *		Print totals even for non-dirs at top level.
 | 
						|
 *		Count blocks for each dir before printing total for the dir.
 | 
						|
 *		Count blocks for all non-special files.
 | 
						|
 *		Don't clutter link buffer with directories.
 | 
						|
 *  1.8:	Remember all links.
 | 
						|
 *  1.9:	Added -x flag to not cross device boundaries.  Type fixes.
 | 
						|
 */
 | 
						|
 | 
						|
 | 
						|
#include <sys/types.h>
 | 
						|
#include <sys/stat.h>
 | 
						|
#include <sys/statfs.h>
 | 
						|
#include <fcntl.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <unistd.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <dirent.h>
 | 
						|
#include <minix/config.h>
 | 
						|
#include <minix/const.h>
 | 
						|
 | 
						|
extern char *optarg;
 | 
						|
extern int optind;
 | 
						|
 | 
						|
#define	LINELEN		256
 | 
						|
#define	NR_ALREADY	512
 | 
						|
 | 
						|
#ifdef S_IFLNK
 | 
						|
#define	LSTAT lstat
 | 
						|
#else
 | 
						|
#define	LSTAT stat
 | 
						|
#endif
 | 
						|
 | 
						|
typedef struct already {
 | 
						|
  struct already *al_next;
 | 
						|
  int al_dev;
 | 
						|
  ino_t al_inum;
 | 
						|
  nlink_t al_nlink;
 | 
						|
} ALREADY;
 | 
						|
 | 
						|
_PROTOTYPE(int main, (int argc, char **argv));
 | 
						|
_PROTOTYPE(int makedname, (char *d, char *f, char *out, int outlen));
 | 
						|
_PROTOTYPE(int done, (Dev_t dev, Ino_t inum, Nlink_t nlink));
 | 
						|
_PROTOTYPE(long dodir, (char *d, int thislev, Dev_t dev));
 | 
						|
 | 
						|
char *prog;			/* program name */
 | 
						|
char *optstr = "asxdl:";	/* options */
 | 
						|
int silent = 0;			/* silent mode */
 | 
						|
int all = 0;			/* all directory entries mode */
 | 
						|
int crosschk = 0;		/* do not cross device boundaries mode */
 | 
						|
char *startdir = ".";		/* starting from here */
 | 
						|
int levels = 20000;		/* # of directory levels to print */
 | 
						|
ALREADY *already[NR_ALREADY];
 | 
						|
int alc;
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	makedname - make the pathname from the directory name, and the
 | 
						|
 *	directory entry, 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;
 | 
						|
  int length;
 | 
						|
 | 
						|
  length = strlen(f);
 | 
						|
  if (strlen(d) + length + 2 > outlen) return(0);
 | 
						|
  for (cp = out; *d; *cp++ = *d++);
 | 
						|
  if (*(cp - 1) != '/') *cp++ = '/';
 | 
						|
  while (length--) *cp++ = *f++;
 | 
						|
  *cp = '\0';
 | 
						|
  return(1);
 | 
						|
}
 | 
						|
 | 
						|
/*
 | 
						|
 *	done - have we encountered (dev, inum) before? Returns 1 for yes,
 | 
						|
 *	0 for no, and remembers (dev, inum, nlink).
 | 
						|
 */
 | 
						|
int done(dev, inum, nlink)
 | 
						|
dev_t dev;
 | 
						|
ino_t inum;
 | 
						|
nlink_t nlink;
 | 
						|
{
 | 
						|
  register ALREADY **pap, *ap;
 | 
						|
 | 
						|
  pap = &already[(unsigned) inum % NR_ALREADY];
 | 
						|
  while ((ap = *pap) != NULL) {
 | 
						|
	if (ap->al_inum == inum && ap->al_dev == dev) {
 | 
						|
		if (--ap->al_nlink == 0) {
 | 
						|
			*pap = ap->al_next;
 | 
						|
			free(ap);
 | 
						|
		}
 | 
						|
		return(1);
 | 
						|
	}
 | 
						|
	pap = &ap->al_next;
 | 
						|
  }
 | 
						|
  if ((ap = malloc(sizeof(*ap))) == NULL) {
 | 
						|
	fprintf(stderr, "du: Out of memory\n");
 | 
						|
	exit(1);
 | 
						|
  }
 | 
						|
  ap->al_next = NULL;
 | 
						|
  ap->al_inum = inum;
 | 
						|
  ap->al_dev = dev;
 | 
						|
  ap->al_nlink = nlink - 1;
 | 
						|
  *pap = ap;
 | 
						|
  return(0);
 | 
						|
}
 | 
						|
 | 
						|
int get_block_size(char *dir, struct stat *st)
 | 
						|
{
 | 
						|
  struct statfs stfs;
 | 
						|
  static int fs_block_size = -1, fs_dev = -1;
 | 
						|
  int d;
 | 
						|
 | 
						|
  if(st->st_dev == fs_dev)
 | 
						|
  	return fs_block_size;
 | 
						|
 | 
						|
  if((d = open(dir, O_RDONLY)) < 0) {
 | 
						|
  	perror(dir);
 | 
						|
  	return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  if(fstatfs(d, &stfs) < 0) {
 | 
						|
  	perror(dir);
 | 
						|
  	return 0;
 | 
						|
  }
 | 
						|
 | 
						|
  fs_block_size = stfs.f_bsize;
 | 
						|
  fs_dev = st->st_dev;
 | 
						|
 | 
						|
  return fs_block_size;
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
/*
 | 
						|
 *	dodir - process the directory d. Return the long size (in blocks)
 | 
						|
 *	of d and its descendants.
 | 
						|
 */
 | 
						|
long dodir(d, thislev, dev)
 | 
						|
char *d;
 | 
						|
int thislev;
 | 
						|
dev_t dev;
 | 
						|
{
 | 
						|
  int maybe_print;
 | 
						|
  struct stat s;
 | 
						|
  long total_kb;
 | 
						|
  char dent[LINELEN];
 | 
						|
  DIR *dp;
 | 
						|
  struct dirent *entry;
 | 
						|
  int block_size;
 | 
						|
 | 
						|
  if (LSTAT(d, &s) < 0) {
 | 
						|
	fprintf(stderr,
 | 
						|
		"%s: %s: %s\n", prog, d, strerror(errno));
 | 
						|
    	return 0L;
 | 
						|
  }
 | 
						|
  if (s.st_dev != dev && dev != 0 && crosschk) return 0;
 | 
						|
  block_size = get_block_size(d, &s);
 | 
						|
  if(block_size < 1) {
 | 
						|
	fprintf(stderr,
 | 
						|
		"%s: %s: funny block size found (%d)\n", 
 | 
						|
			prog, d, block_size);
 | 
						|
    	return 0L;
 | 
						|
  }
 | 
						|
  total_kb = ((s.st_size + (block_size - 1)) / block_size) * block_size / 1024;
 | 
						|
  switch (s.st_mode & S_IFMT) {
 | 
						|
    case S_IFDIR:
 | 
						|
	/* Directories should not be linked except to "." and "..", so this
 | 
						|
	 * directory should not already have been done.
 | 
						|
	 */
 | 
						|
	maybe_print = !silent;
 | 
						|
	if ((dp = opendir(d)) == NULL) break;
 | 
						|
	while ((entry = readdir(dp)) != NULL) {
 | 
						|
		if (strcmp(entry->d_name, ".") == 0 ||
 | 
						|
		    strcmp(entry->d_name, "..") == 0)
 | 
						|
			continue;
 | 
						|
		if (!makedname(d, entry->d_name, dent, sizeof(dent))) continue;
 | 
						|
		total_kb += dodir(dent, thislev - 1, s.st_dev);
 | 
						|
	}
 | 
						|
	closedir(dp);
 | 
						|
	break;
 | 
						|
    case S_IFBLK:
 | 
						|
    case S_IFCHR:
 | 
						|
	/* st_size for special files is not related to blocks used. */
 | 
						|
	total_kb = 0;
 | 
						|
	/* Fall through. */
 | 
						|
    default:
 | 
						|
	if (s.st_nlink > 1 && done(s.st_dev, s.st_ino, s.st_nlink)) return 0L;
 | 
						|
	maybe_print = all;
 | 
						|
	break;
 | 
						|
  }
 | 
						|
  if (thislev >= levels || (maybe_print && thislev >= 0)) {
 | 
						|
	printf("%ld\t%s\n", total_kb, d);
 | 
						|
  }
 | 
						|
  return(total_kb);
 | 
						|
}
 | 
						|
 | 
						|
int main(argc, argv)
 | 
						|
int argc;
 | 
						|
char **argv;
 | 
						|
{
 | 
						|
  int c;
 | 
						|
 | 
						|
  prog = argv[0];
 | 
						|
  while ((c = getopt(argc, argv, optstr)) != EOF) switch (c) {
 | 
						|
	    case 'a':	all = 1;	break;
 | 
						|
	    case 's':	silent = 1;	break;
 | 
						|
	    case 'x':
 | 
						|
	    case 'd':	crosschk = 1;	break;
 | 
						|
	    case 'l':	levels = atoi(optarg);	break;
 | 
						|
	    default:
 | 
						|
		fprintf(stderr,
 | 
						|
			"Usage: %s [-asx] [-l levels] [startdir]\n", prog);
 | 
						|
		exit(1);
 | 
						|
	}
 | 
						|
  do {
 | 
						|
	if (optind < argc) startdir = argv[optind++];
 | 
						|
	alc = 0;
 | 
						|
	(void) dodir(startdir, levels, 0);
 | 
						|
  } while (optind < argc);
 | 
						|
  return(0);
 | 
						|
}
 |