/*
 * donate person[:mode] file ...
 *
 * -r - recursively descend directories encountered
 * -f - force (inode 2 even)
 * -i - inquire at each directory (if -r)
 * -v - operate verbosely, tell each file as we go along
 *
 * John Buck -- PINY 8/83
 */

/* Size of max path length */
#define	NPATH	5120

#include <stdio.h>
#include <sys/types.h>
#include "hsubs.h"
#include <sys/stat.h>
#include <sys/dir.h>

struct	direct	direct;

int	errcode;
short uid, gid;
short mode;

char vflg, iflg, rflg, fflg;
char buf[NPATH];
char *owner;

main(argc, argv)
char *argv[];
{
	register char *arg;
	register char *p;
	register short i;

	if((i = getgid()) && i != 2 && getuid()){
		fprintf(stderr, "donate: Permission denied.\n");
		exit(1);
	}
	mode = -1;
	vflg = 0;
	iflg = 0;
	rflg = 0;
	fflg = 0;
	if(argc>1 && argv[1][0]=='-') {
		arg = *++argv;
		argc--;
		while(*++arg != '\0')
			switch(*arg) {
			case 'f':
				fflg++;
				break;

			case 'v':
				vflg++;
				break;
			case 'i':
				if(isatty(0))
					iflg++;
				break;
			case 'r':
				rflg++;
				break;
			default:
usg:
				fprintf(stderr, "Usage: donate [-ivrf] owner[:mode] file ...\n");
				exit(1);
			}
	}
	if(argc-- < 3)
		goto usg;
	arg = *++argv;
	p = arg;
	while(*p && *p != ':')
		p++;
	if(*p){
		*p++ = '\0';
		if((mode = atoo(p)) == -1)
			exit(1);
	}
	if(getid(arg))
		exit(1);
	owner = arg;
	while(--argc > 0) {
		strcpy(buf, *++argv);
		donate(buf + strlen(buf), 0);
	}
	exit(errcode);
}

donate(pl, level)
register char *pl;
{
	struct stat statb;
	register char *s, *l;
	int d;

	if(stat(buf, &statb)) {
		printf("donate: %s nonexistent\n", buf);
		++errcode;
		return;
	}
	if (statb.st_ino == 2 && !fflg) {
		fprintf(stderr, "donate: %s: not advisable\n", buf);
		return;
	}
	if ((statb.st_mode&S_IFMT) == S_IFDIR && rflg) {
		if(iflg && level) {
			printf("Directory %s: ", buf);
			if(!yes())
				return;
		}
		if((d=open(buf, 0)) < 0) {
			fprintf(stderr, "donate: %s can not read\n", buf);
			errcode++;
			return;
		}
		*pl = '/';
		while(read(d, (char *)&direct, sizeof(direct)) == sizeof(direct)) {
			if(direct.d_ino == 0 || dotname(direct.d_name))
				continue;
			for(l = pl + 1, s = direct.d_name; 
				*s && s < &direct.d_name[DIRSIZ];){
				if(l >= &buf[NPATH-10]){
					fprintf(stderr, "donate: too deep %d\n", level);
					errcode++;
					*pl = '\0';
					return;
				}
				*l++ = *s++;
			}
			*l = '\0';
			donate(l, level+1);
		}
		*pl = '\0';
		close(d);
	}

	if(vflg){
		printf("%s - \"%s\" ", buf, owner);
		if(mode >= 0)
			printf("0%o", mode);
		printf("\n");
	}
	if(chown(buf, uid, gid)){
		fprintf(stderr, "donate: %s: can not change owner\n", buf);
		errcode++;
	}
	if(mode >= 0)
		if(chmod(buf, mode)){
			fprintf(stderr, "donate: %s: can not change mode\n", buf);
			errcode++;
		}
}

dotname(s)
char *s;
{
	if(s[0] == '.')
		if(s[1] == '.')
			if(s[2] == '\0')
				return(1);
			else
				return(0);
		else if(s[1] == '\0')
			return(1);
	return(0);
}

yes()
{
	int i, b;

	i = b = getchar();
	while(b != '\n' && b != EOF)
		b = getchar();
	return(i == 'y');
}

getid(n)
char *n;
{
	register char *s;

	if(ngetent(HFILE_NM, n, buf)){
		fprintf(stderr, "donate: %s: invalid user\n", n);
		return(1);
	}
	s = buf;
	while(*s++ != ':');
	while(*s++ != ':');
	uid = atoi(s);
	while(*s++ != ':');
	gid = atoi(s);
	return(0);
}

atoo(s)
register char *s;
{
	register short i;

	i = 0;
	while(*s){
		if(*s < '0' || *s > '7' || i > 07777){
numerr:
			fprintf(stderr, "donate: Bad number for mode\n");
			return(-1);
		}
		i = (i << 3) + (*s++ - '0');
	}
	if(i > 07777)
		goto numerr;
	return(i);
}

