#ifdef DEBUG
#define DFILE "accttmp"
#endif


/*
 *	Polytechnic UNIX accounting Package - Program: da.c
 *
 *	Author:	John Buck
 *	Polytechnic Institute NY, September 1981
 *
 *	Program Description:
 *		Program will skip through mounted filesystems and tally
 *		up disk usage for each gid/uid pair, and add it to the
 *		current figures for disk usage of the uid/gid pair.
 *
 */



#include	"sys/types.h"
#include	"mnttab.h"
#include	"hsubs.h"
#include	"actrecs.h"
#include	"sys/param.h"
#include	"sys/ino.h"
#include	"sys/filsys.h"

struct	acctrec	arec;
#define	NUMIN	16*INOPB

struct	filsys	sblock;
struct	dinode	inode[NUMIN];
struct mnttab	mount[NMOUNT], *pm;


int	fi , base , top , af , ino;
char	*file;
struct	dtab {
	short	hid;
	short	hgd;
	long	value;
}dtab[NHENT];


main(){
	register i , r , d;
	static char device[32];

	if(done())exit(0);
	if((fi = open("/etc/mnttab",0)) == -1)
		error("No mount table: /etc/mnttab\n");
	if((af = open(DFILE,2)) == -1)
		error("No disk record file\n");
	if((r = read(fi,mount,sizeof mount)) % (sizeof (struct mnttab)))
		error("Bad byte count for mount table\n");

	close(fi);

	r /= (sizeof (struct mnttab));
	for(pm = &mount[0]; pm < &mount[r]; pm++) {
		if(pm->mt_filsys[0] == 0 || pm->mt_dev[0] == 0)
			continue;
		if(pm->mt_ro_flg){
			printf("da: Bypassing read/only filesystem: %s\n",
				pm->mt_dev);
			continue;
		}
		sync();
		strcpy(device, "/dev/r");
		strncat(device, pm->mt_dev, 10);
#ifdef	DEBUG
		printf("%s:\n", device);
#endif
		if((fi = open(device,0)) == -1){
			printf("da: Can't open %s\n", device);
			continue;
		}
		file = pm->mt_filsys;
		doit();
		close(fi);
	}
	writit();
	close(af);
	exit(0);
}


doit(){
	register int nf , i , j;

	bread(1L,&sblock,(sizeof sblock));
	nf = (sblock.s_isize-2)*INOPB;

	for(i = ino = 0; ino < nf; i =+ NUMIN/INOPB){
		bread((long)(i+2), inode, sizeof inode);
		for(j = 0; j < NUMIN && ino < nf; j++){
			ino++;
			add(&inode[j]);
		}
	}
}


add(pi)
struct dinode *pi;
{
	register int g,u;
	register short hk;
	char oncethru;

	if(pi->di_mode == 0)return;
	g = pi->di_gid;
	u = pi->di_uid;
	oncethru = 0;
	if(ignore(g,u))return;

	hk = akey(u);
lp:
	if(dtab[hk].hgd != g || dtab[hk].hid != u){
		if(dtab[hk].hid == 0 && dtab[hk].hgd == 0){
			dtab[hk].hid = u;
			dtab[hk].hgd = g;
		} else {
			if(++hk >= NHENT){
				if(oncethru++){
					error("HASH TABLE FULL!!!!!!!");
				}
				hk = 0;
			}
			goto lp;
		}
	}
	dtab[hk].value += (pi->di_size + 511) >> 9;
}

bread(b,bf,cn)
long b;
{
	lseek(fi, b << 9, 0);
	if(read(fi,bf,cn) != cn)
		error("bread: bad count for disk I/O\n");
}

ignore(g,u)
register g,u;
{
/*
	switch(g){

	case	0:
	case	3:
		return(1);
	default:
		break;
	}
*/



	switch(u){
			/* cases are lists of uids to NOT do disk
			   accounting on!! */
	case	68:
	case 9:
		return(1);
	default:
		return(0);
	}
}



error(s)
char *s;
{
	printf("da: %s\n",s);
	exit(1);
}



done(){
	static char *f = "/accting/dalock.00000";
	register char *s;
	register int *l , i;
	int *localtime() , statb[36];

	time(statb);
	l = localtime(statb);

#ifndef	DEBUG
	if(l[6] == 0)return(1);	/* Sunday */
#endif
	s = f + 17;
	i = l[5];
	while(i){
		*s-- = i%10 + '0';
		i =/ 10;
	}

	s = f + 20;
	i = l[7];
	while(i){
		*s-- = i%10 + '0';
		i =/ 10;
	}

	if(stat(f,statb) == 0)return(1);
	if((i = fork()) == -1)goto skip;
	if(i == 0){
		execl("/bin/sh","sh","-c","/bin/rm -f /accting/dalock.*",0);
		exit(1);
	}
	wait(statb);

skip:
	if(close(creat(f,0600)) == -1)return(1);
	return(0);
}

writit()
{
	register int i, err, hk;

	for(i = 0; i < NHENT; i++){
		if(dtab[i].value == 0L)continue;
		if(dtab[i].hgd == 0 && dtab[i].hid == 0)
			dtab[i].hgd = 255;
		hk = dtab[i].hid;
		lseek(af, (long)(akey(hk)) * AREAD, 0);
		err = 0;
lp:
		if(read(af, &arec, AREAD) != AREAD){
			if(err++)error("read error");
			lseek(af, 0L, 0);
			goto lp;
		}
		if(arec.a_gid != dtab[i].hgd || arec.a_uid != dtab[i].hid){
			if(arec.a_uid == 0 && arec.a_gid == 0){
				arec.a_uid = dtab[i].hid;
				arec.a_gid = dtab[i].hgd;
			} else
				goto lp;
		}
		arec.a_diskblks += dtab[i].value;
		lseek(af, -(long)AREAD, 1);
		write(af, &arec, AREAD);
#ifdef	DEBUG
		printf("U:%-5d G:%-5d  Disk:%7D\n", arec.a_uid, arec.a_gid,
			arec.a_diskblks);
#endif
	}
	close(af);
}
