
#include	"/usr/include/sys/param.h"
#include	"/usr/include/sys/filsys.h"
#include	"/usr/include/sys/stat.h"
#include	"/usr/include/sys/ino.h"
#include	"quotas.h"

struct	filsys	sblk;
struct	dinode	inode[256];
struct stat	statb;
struct	qent	q;
int	qfd;

char	*QFILE = QUOFILE;

main(c,v)
char **v;
{
	register i;
	register char *s;
	register uint	ent;
	char **vv, **arglist;
	short cc;

	if(c < 2){
		printf("Usage: chgquo username [-update] [-d dollarquo] ");
               printf("[-m newmoney]\n");
              printf("\t[-o uid] [-g gid] [-nonotify] [-reset] [-p /path]\n");
               printf("\t[-b blockquo] [-f newfilequo] [-warnonly]");
		printf(" [-i moneyinc]\n");
		exit(1);
	}

	cc = c;
	arglist = vv = v;
	while(**++vv != '-' && *vv)
		cc--;
	if((qfd = open(QFILE, 2)) == -1){
bad:
		printf("chgquo:	Can not get to %s\n", QFILE);
		exit(2);
	}

	vv--;
	while(**++arglist != '-' && *arglist){
		v = vv;
		c = cc;
		if((ent = getqent(qfd, &q, *arglist)) == 0){
			printf("chgquo: User \"%s\" not found\n", *arglist);
			continue;
		}
		lseek(qfd, (long)(ent)*QSZ, 0);
		while(--c){
			v++;
			switch(v[0][1]){
	
		case 'r':
			q.q_flg =& ~037;
			break;
	
		case 'u':
			check();
			break;
	
		case 'o':
			if(--c){
				i = atoi(*++v);
				q.q_uid = i;
			} else c++;
			break;
	
		case 'g':
			if(--c){
				i = atoi(*++v);
				q.q_gid = i;
			} else c++;
			break;
	
		case 'n':
				q.q_flg =^ 040;
				break;
	
		case 'w':
				q.q_flg =^ ~077;
				break;
	
		case 'd':
			if(--c){
				i = atoi(*++v)*10;
				if(i < 0)
					printf("Illegal quota %u\n", i);
				else	q.q_mquo = i;
			} else c++;
			break;
	
		case 'm':
			if(--c){
				i = atoi(*++v);
				i *= 10;
				if(i < 0)
					printf("Illegal usage %u\n", i);
				else	q.q_mused = i;
			} else c++;
			break;

		case 'i':
			if(--c){
				i = atoi(*++v);
				if(i < 0 || i > 127)
					printf("Illegal increment %u\n", i);
				else	q.q_inc = i;
			} else c++;
			break;

	
		case 'b':
				if(--c){
					i = atoi(*++v);
					if(i < 0)printf("Illegal quota %u\n", i);
					else	q.q_dquo = i;
				}
				else	c++;
				break;
	
		case 'f':
				if(--c){
					i = atoi(*++v);
					if(i < 0)printf("Illegal quota %u\n", i);
					else	q.q_fquo = i;
				}
				else	c++;
				break;
	
		case 'p':
			if(--c){
				v++;
				s = *v;
				if(*s != '/'){
	badpath:
					printf("Illegal path: %s\n", s);
					break;
				}
				while(*++s)
					if(*s == '/'){
						*s = 0;
						break;
					}
				if(strlen(s = *v) > 7)
					goto badpath;
				if(stat(s, &statb)){
					printf("Pathname non-existant: %s\n", s);
					break;
				}
				strncpy(q.q_fs, ++s, 6);
			}
			else	c++;
			break;
	
		default:
				printf("Illegal option %c\n", v[0][1]);
				exit(4);
			}
		}
		ckquo();
		write(qfd, &q, QSZ);
	}
	close(qfd);
	exit(0);
}


check()
{
	char *dev = "/dev/rrmxx";
	register nf, i, j;
	char *p;
	int fs;
	char	dbuf[14];

	p = dev+8;
	dbuf[0] = '/';
	strncpy(dbuf+1, q.q_fs, 6);
	dbuf[7] = 0;
	if(stat(dbuf, &statb)){
		printf("chgquo: Can not stat %s\n", dbuf);
		exit(5);
	}
	if((statb.st_dev =& 0377) > 9) *p++ = '1';
	*p++ = statb.st_dev%10 + '0';
	*p = 0;
	if((fs = open(dev, 0)) == -1){
		printf("chgquo: Can not open disk %s\n", dev);
		exit(6);
	}
	sync();
	lseek(fs, 512L, 0);
	if(read(fs, &sblk, sizeof (sblk)) != sizeof (sblk)){
		printf("chgquo: Bad super block read \n");
		exit(7);
	}
	nf = (sblk.s_isize - 2)*INOPB;
	q.q_dused = q.q_fused = 0;
	for(i = 0; i < nf; i++){
		if((j = (i & 0377)) == 0){
			if(read(fs, inode, sizeof inode) != sizeof inode){
				printf("chgquo: %s bad inode block read\n", dev);
				exit(8);
			}
		}
		lookup(&inode[j]);
	}
	close(fs);
	return;
}

lookup(ip)
register struct dinode *ip;
{
	if(ip->di_mode == 0)return;
	if((ip->di_gid != q.q_gid && q.q_gid != -1) ||
	   (ip->di_uid != q.q_uid && q.q_uid != -1))return;
	q.q_fused++;
	q.q_dused += (unsigned)((long)(ip->di_size + 511) >> 9L);
	return;
}

