#ifndef lint
static char *sccsid = "@(#)rquot.c	1.3 (UKC) 21/11/88";
#endif  lint
/*
 *	Rquot: tot up disk usage per user.
 *
 *	Usage:  rquot [dir] ...
 *
 *	Output is the number of data bytes for each user.
 *	The wasted space due to partially-filled disk blocks is not accounted.
 *	
 *	Martin Guy, UKC, September 1986.
 */
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <pwd.h>
#include <signal.h>

#define MAXUIDS 65536		/* Should be dynamic. Yes, I'm lazy. */

int diskusage[MAXUIDS];		/* in blocks, initialised to 0 */

int addquot();
int coredump();

char *progname;		/* argv[0] for error reporting */

main(argc,argv)
char **argv;
{
	int i;		/* index into argv */

	progname = argv[0];

	/* Else it's a real bugger trying to find core dumps from this thing! */
	(void) signal(SIGSEGV, coredump);
	(void) signal(SIGFPE, coredump);
	(void) signal(SIGBUS, coredump);

	/* default is from current directory.  Remake arg[cv]. */
	if (argc < 2) {
		static char *argv2[] = { (char *) 0, "." };

		argv2[0] = argv[0];	/* copy progname across */
		argv = argv2;
		argc = 2;
	}

	for (i=1; i<argc; i++) {
		if (descend(argv[i], addquot) < 0) {
			fprintf(stderr, "%s: descent failed on \"%s\".", progname, argv[i]);
		}
	}

	printusage();
}

/*
 * Arguments to fn are:
 * name of file relative to cwd.
 * full name of file from starting directory.
 * pointer to stat structure for that file.
 *	(may be NULL if not stattable)
 */
int
addquot(name, fullname, stbuf)
char *name;
char *fullname;
struct stat *stbuf;
{
	register int uid;	/* local copy from stbuf */

	if (stbuf == NULL) return(0);
	switch (stbuf->st_mode & S_IFMT) {
	case S_IFREG:
		uid = stbuf->st_uid;
		if (uid < 0 || uid >= MAXUIDS) {
			fprintf(stderr, "%s: Outsize uid %d on %s.\n", progname, uid, fullname);
		} else {
			diskusage[stbuf->st_uid] += stbuf->st_size
						  / stbuf->st_nlink;
		}
	}
	return(1);
}

int
coredump(sig)
int sig;
{
	(void) chdir("/tmp");
	(void) signal(sig, SIG_DFL);
	kill(getpid(), sig);
	abort();
}

printusage()
{
	register struct passwd *pp;
	register int i;

	setpwent();

	while ( (pp = getpwent()) != NULL ) {
		i = diskusage[pp->pw_uid];	/* copy for conciseness */
		if (i != 0) {
			printf("%s\t%d\n", pp->pw_name, i);
			diskusage[pp->pw_uid] = 0;	/* for final scan */
		}
	}
	endpwent();

	/* scan for files with no owner */
	for (i=0; i<MAXUIDS; i++) {
		if (diskusage[i] != 0) {
			printf("#%d\t%d\n", i, diskusage[i]);
		}
	}
}
