[alt.sources] ndu -- news disk usage

dt@yenta.alb.nm.us (David B. Thomas) (11/15/90)

I just wrote a handy disk usage analyzer for news that I call "ndu",
"news disk usage".  Like everything in unix, there is probably some
wonderful command I've never noticed that does exactly the same thing
this program does, only much better.  Then again, like everything in
unix, this was fun to write!

It tells you, for each newsgroup, how much space it uses (excluding
subdirectories, unlike du(1)), how many articles are online, and the age
of the oldest article.

The output is in a format suitable for crunching by sort, awk, and them
cats.

----- begin readme -----

ndu -- "news disk usage"

ndu is a useful tool for analyzing the /usr/spool/news directory tree.

While ndu can be used to gather information about any directory tree, it
was designed to analyze /usr/spool/news, and will do so by default.

Usage is:		ndu [ directory ]

The output shows, for each subdirectory (newsgroup) encountered, space
used (in kb), number of files (articles), and the age of oldest file in days.

The format of the output is suitable for feeding to sort, awk, and many other
nifty tools to help you analyze what's there.


Some sample output:

   23    40     3   ./misc/test
   71    46     1   ./misc/consumers/house
   58    37     1   ./misc/consumers
  144    52     1   ./misc/legal
   71    67     3   ./misc/wanted
   96    50     3   ./misc/invest
  136    57     1   ./misc/kids
  193   146     3   ./misc/forsale/computers
  222   169     3   ./misc/forsale
  ^^^-------------------------------------------space used in kb
	^^^-------------------------------------number of articles
		^-------------------------------age in days of oldest article


Space and number of articles do not include subdirectories or their contents.
Note that misc/consumers/house exceeds misc/consumers in both space used and
number of articles.

Age is rounded down to the nearest day, so a 0 simply means that all files
in that directory are less than 24 hours old.

BUGS
      -	All file names are listed beginning with "./".
      -	It does not convert the paths to newsgroup names with periods.
      -	It reads directories primitive-unix-style, so it probably won't
work on a non-unix system without some minor hacking.  Oh well, life is
long and the program is short :-)

----- end readme -----
----- begin ndu.c -----

/*
 * ndu.c	-- news disk usage
 *
 *	usage:	ndu [ directory ]
 *
 * generates a disk usage report for all directories subordinate to and
 * including the path specified (default /usr/spool/news).
 *
 * Each line in the report shows space used in kb, number of files, and the
 * age of the oldest file in days.  Space and number of files exclude
 * subdirectories and their contents, unlike du(1).
 *
 * Crufted up by: David B. Thomas <dt@yenta.alb.nm.us>
 *
 * This program is free and you can do anything you want with it, including
 * saving me some embarrassment by claiming you wrote it!
 *						-dt
 */

#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <malloc.h>

#define	SECINDAY	(24 * 3600)

int	dirfunc();

char	*progname,
	*topdir = "/usr/spool/news";

time_t	now;


main(argc,argv)
int	argc;
char	*argv[];
{
	progname = argv[0];

	switch (argc) {
	    case 2:
		topdir = argv[1];
		/* fallthru */
	    case 1:
		break;
	    default:
		fprintf (stderr, "usage: %s [ directory ]\n", progname);
		exit (-1);
	}

	time(&now);
	chdir (topdir);
	dodir (".");

	exit (0);
} /* main() */


/*
 * dodir(path)
 *	recursively explores directory specified by path, tallying and
 * reporting info as it goes.
 */

dodir(path)
char	*path;
{
	/* these must be stacked */
	int			fd,
				nfiles = 0;
	size_t			size = 0;
	time_t			oldest = now;
	char			*fullpath;
	/* these can be overwritten -- one static copy ok */
	static char		fname[DIRSIZ+1];
	static struct direct	dir;
	static struct stat	stt;


	if ( (fd = open (path, O_RDONLY)) == -1) {
		fprintf (stderr, "%s: can't read %s\n", progname, path);
		return;
	}

	while (read(fd, &dir, sizeof(struct direct)) == sizeof(struct direct)) {

		/* make a null-terminated string with the filename */
		strncpy (fname, dir.d_name, DIRSIZ);
		fname[DIRSIZ] = '\0';

		/* skip . and .. and empty dir slots */
		if (!dir.d_ino ||
		    !strcmp(fname,".") ||
		    !strcmp(fname,"..")  )
			continue;

		/* build the full path of this file */
		fullpath = malloc (strlen(path)+strlen(fname)+2);
		sprintf (fullpath, "%s/%s", path, fname);

		if (stat(fullpath, &stt) == -1) {
			fprintf (stderr,
			    "%s: cannot stat %s\n", progname, fullpath);
			free (fullpath);
			continue;
		}
		if (stt.st_mode & S_IFDIR) {
			dodir (fullpath);
			free (fullpath);
			continue;
		}
		free (fullpath);
		if (stt.st_mtime < oldest)
			oldest = stt.st_mtime;
		size += stt.st_size;
		++nfiles;
	}
	close (fd);
	/* report size in kb, number of articles, age of oldest in days */
	if (nfiles)
		printf ("%5d %5d %5d   %s\n", size/1000, nfiles,
		    (now-oldest) / SECINDAY, path);
} /* dodir() */
----- end ndu.c -----

Please send me any comments, mods, etc.		--little david
-- 
You mean you WUZ a Romanian....MUTHA!