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

#define		PLAYDATA	"/usr/games/play.data"
struct stat statb;
struct utmp who;

char buf[128];
char dbuf[514];

struct	game	{
	char *g_path;
	short	g_mode;
} *game, ptr;

struct game	*getgame();

main(argc, argv)
char **argv;
{
	long tim;
	int *pt;
	short whocnt, fd;
	short f;
	short gid;
	register char *s;
	FILE *fp;

	if(argc < 2){
		printf("Usage: play game args ...\n");
listmsg:
		printf("Type 'play list' for a list of valid games\n\n");
		exit(1);
	}
	if((game = getgame(argv[1])) == NULL){
		printf("%s: '%s' is not a valid game\n\n", argv[0], argv[1]);
		goto listmsg;
	}
	gid = getgid();
	gid = (gid && gid != 2);
	time(&tim);
	pt = localtime(&tim);
	if(pt[4] &&
	 ((pt[4] < 4 || pt[4] > 8) ||
	  (pt[4] == 8  && pt[3] > 7) ||
	  (pt[4] == 4 && pt[3] < 15)) &&
	 pt[6] != 0 && pt[6] != 6 && pt[2] > 6 && pt[2] < 21){
		printf("Games%sare not allowed at this time.\n",
			gid ? " " : " for normal users ");
		if(gid)
			exit(1);
		printf("\n");
	}
	whocnt = 0;
	if((fd = open(UTMP_FILE, 0)) == -1){
		printf("No utmp\n");
		exit(2);
	}
	while(read(fd, &who, sizeof (struct utmp)) == sizeof (struct utmp)){
		if(who.ut_name[0] &&
			 who.ut_name[0] != ' ' && who.ut_type == USER_PROCESS)
			whocnt++;
	}
	close(fd);
	if(whocnt > 15){
		if(gid){
			printf("System load is too heavy now (%d) -- try later.\n",
				whocnt);
			sleep(5);
			exit(3);
		}
		printf("System load is heavy now (%d) -- ", whocnt);
		printf("please do not play too long.\n\n");
	}
okay:
	if(stat(game->g_path, &statb)){
		printf("%s: not found\n", argv[1]);
		exit(7);
	}
	if(strcmp(game->g_path, "/usr/games/empire/empire") == 0 && !isatty(0)){
		printf("Stdin is not standard.\n");
		exit(2);
	}
	for(f = 0; f < 17; f++)
		signal(f, 1);
	chmod(game->g_path, statb.st_mode | 0111);
	if((f = fork()) == 0){
		setpgrp(-1);
		if((fp = fopen("/usr/adm/.gamelog", "a")) != NULL){
			time(&tim);
			fprintf(fp, "%-8.8s: %-8.8s played %s on %s",
				logname(), logtty(), buf, ctime(&tim));
			fclose(fp);
		}
		sleep(2);
		chmod(game->g_path, (statb.st_mode & ~0777) | game->g_mode);
		exit(0);
	}
	setuid(getuid());
	setgid(getgid());
	for(f = 0; f < 17; f++)
		signal(f, 0);
	execv(game->g_path, &argv[1]);
	printf("%s: not found\n", argv[1]);
	exit(4);
}

struct game *
getgame(s)
char *s;
{
	register char *t, *p;
	register char *l;
	short listflg;
	short fd;
	short r;
	short i;

	listflg = (strcmp("list", s) == 0);
	if((fd = open(PLAYDATA, 0)) == -1){
		printf("No games are available\n");
		exit(2);
	}

	t = buf;
	while((r = read(fd, dbuf, 512)) > 0){
		p = dbuf;
		l = p + r;
		*l = 0;
		while(p < l){
			if((*t++ = *p++) != '\n')
				continue;
			*--t = 0;
			t = strchr(buf, ':');
			if(t == NULL){
bad:
				printf("Bad line in game data base\n");
				exit(3);
			}
			*t++ = 0;
			if(listflg){
				if(listflg == 1){
					listflg = 6;
				} else {
					printf("%-15.15s", buf);
					i = 0;
					if(strlen(buf) > 15){
						printf("%-15.15s", buf+15);
						i = 1;
					}
					if(listflg++ % 5 == 0 ||
					    (i && listflg++ % 5 == 0)){
						printf("\n");
					}
				}
				t = buf;
				continue;
			}
			if(!cclmat(buf, s)){
				t = buf;
				continue;
			}
			ptr.g_path = t;
			t = strchr(t, ':');
			if(t == NULL)
				goto bad;
			*t++ = 0;
			ptr.g_mode = 0;
			while(*t >= '0' && *t <= '7')
				ptr.g_mode = (ptr.g_mode << 3) | ((*t++) - '0');
			ptr.g_mode &= 0777;
			close(fd);
			return(&ptr);
		}
	}
	close(fd);
	if(listflg){
		printf("\n\n'-' indicates point of minimum abbreviation.\n\n");
		exit(0);
	}
	return(NULL);
}

cclmat(p, s)
register char *p, *s;
{
	register char *t;

	t = p;
	while(*p != '-' && *p)
		p++;
	if(strncmp(t, s, p-t))
		return(0);
	s += p-t;
	if(*p++ == 0)
		return(*s == 0);
	t = s;
	while(*s)
		s++;
	if(strncmp(t, p, s-t))
		return(0);
	return(1);
}
