xref: /csrg-svn/games/dm/dm.c (revision 32245)
132216Sbostic /*
232216Sbostic  * Copyright (c) 1987 Regents of the University of California.
332216Sbostic  * All rights reserved.  The Berkeley software License Agreement
432216Sbostic  * specifies the terms and conditions for redistribution.
532216Sbostic  */
632216Sbostic 
732216Sbostic #ifndef lint
832216Sbostic char copyright[] =
932216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
1032216Sbostic  All rights reserved.\n";
1132216Sbostic #endif not lint
1232216Sbostic 
1332216Sbostic #ifndef lint
14*32245Sbostic static char sccsid[] = "@(#)dm.c	5.3 (Berkeley) 09/21/87";
1532216Sbostic #endif not lint
1632216Sbostic 
1732216Sbostic #include <sys/param.h>
1832216Sbostic #include <sys/file.h>
1932216Sbostic #include <sys/time.h>
2032216Sbostic #include <sys/resource.h>
2132216Sbostic #include <pwd.h>
2232216Sbostic #include <utmp.h>
2332216Sbostic #include <nlist.h>
2432216Sbostic #include <stdio.h>
2532216Sbostic #include <ctype.h>
2632216Sbostic 
2732216Sbostic #define	GAMEHIDE	"/usr/games/hide"
28*32245Sbostic #define	NOGAMING	"/usr/games/nogames"
29*32245Sbostic #define	CONTROL		"/usr/games/dm.config"
3032216Sbostic #ifdef LOG
31*32245Sbostic #define	LOGFILE		"/usr/adm/dm.log"
3232216Sbostic #endif
3332216Sbostic 
3432227Sbostic static FILE	*cfp;
3532216Sbostic static time_t	now;			/* current time value */
3632227Sbostic static int	priority = 0;		/* priority game runs at */
3732227Sbostic static char	*game,			/* requested game */
3832227Sbostic 		*gametty;		/* from tty? */
3932216Sbostic 
4032216Sbostic main(argc, argv)
4132216Sbostic 	int	argc;
4232216Sbostic 	char	**argv;
4332216Sbostic {
4432227Sbostic 	char	*C, *rindex();
4532216Sbostic 	double	load();
4632216Sbostic 
4732216Sbostic 	nogamefile();
4832216Sbostic 
4932227Sbostic 	if (!strcmp(*argv, "dm"))
5032227Sbostic 		exit(0);
5132216Sbostic 
5232227Sbostic 	if (!(cfp = fopen(CONTROL, "r"))) {
5332216Sbostic 		fprintf(stderr, "dm: unable to read %s.\n", CONTROL);
5432216Sbostic 		exit(1);
5532216Sbostic 	}
5632216Sbostic 
5732227Sbostic 	read_days();
5832227Sbostic 	read_ttys();
5932216Sbostic 
6032216Sbostic 	game = (C = rindex(*argv, '/')) ? ++C : *argv;
6132227Sbostic 	read_games();
6232216Sbostic 
6332216Sbostic #ifdef LOG
6432216Sbostic 	logfile();
6532216Sbostic #endif
6632216Sbostic 	play(argv);
6732227Sbostic /*NOTREACHED*/
6832216Sbostic }
6932216Sbostic 
7032216Sbostic /*
7132216Sbostic  * play --
7232216Sbostic  *	play the game
7332216Sbostic  */
7432216Sbostic static
7532216Sbostic play(args)
7632216Sbostic 	char	**args;
7732216Sbostic {
7832216Sbostic 	if (chdir(GAMEHIDE)) {
7932216Sbostic 		perror("dm: chdir");
8032216Sbostic 		exit(1);
8132216Sbostic 	}
82*32245Sbostic 	if (priority > 0 && setpriority(PRIO_PROCESS, 0, priority) < 0)
8332216Sbostic 		fputs("dm: unable to set priority!\n", stderr);
8432227Sbostic 	setgid(getgid());	/* we run setgid kmem; lose it */
8532216Sbostic 	execv(game, args);
8632227Sbostic 	perror("dm");
8732216Sbostic 	exit(1);
8832216Sbostic }
8932216Sbostic 
9032227Sbostic #define	lcontrol(buf)	(buf[0] == '%' && buf[1] == '%')
9132227Sbostic #define	lignore(buf)	(buf[0] == '\n' || buf[0] == '#')
9232216Sbostic /*
9332216Sbostic  * read_days --
9432227Sbostic  *	read through days listed in the control file, decide
9532227Sbostic  *	if current time is an okay play time.
9632216Sbostic  */
9732216Sbostic static
9832227Sbostic read_days()
9932216Sbostic {
10032227Sbostic 	static char	*days[] = {
10132227Sbostic 		"sunday", "monday", "tuesday", "wednesday",
10232227Sbostic 		"thursday", "friday", "saturday",
10332227Sbostic 	};
10432227Sbostic 	struct tm	*ct;
10532227Sbostic 	register char	*dp;
10632227Sbostic 	int	start, stop;
10732227Sbostic 	char	lbuf[BUFSIZ], f1[40], f2[40], f3[40];
10832227Sbostic 	time_t	time();
10932216Sbostic 
11032227Sbostic 	(void)time(&now);
11132227Sbostic 	ct = localtime(&now);
11232227Sbostic 	dp = days[ct->tm_wday];
11332227Sbostic 
11432227Sbostic 	while (fgets(lbuf, sizeof(lbuf), cfp)) {
11532227Sbostic 		if (lignore(lbuf))
11632216Sbostic 			continue;
11732227Sbostic 		if (lcontrol(lbuf))
11832216Sbostic 			return;
11932227Sbostic 		if (sscanf(lbuf, "%s%s%s", f1, f2, f3) != 3)
12032216Sbostic 			continue;
12132227Sbostic 		if (!strcasecmp(dp, f1)) {
12232227Sbostic 			if (!isdigit(*f2) || !isdigit(*f3))
12332227Sbostic 				continue;
12432227Sbostic 			start = atoi(f2);
12532227Sbostic 			stop = atoi(f3);
12632227Sbostic 			if (ct->tm_hour >= start && ct->tm_hour <= stop) {
12732227Sbostic 				fputs("dm: Sorry, games are not available from ", stderr);
12832227Sbostic 				hour(start);
12932227Sbostic 				fputs(" to ", stderr);
13032227Sbostic 				hour(stop);
13132227Sbostic 				fputs(" today.\n", stderr);
13232227Sbostic 				exit(0);
13332216Sbostic 			}
13432227Sbostic 			continue;
13532227Sbostic 		}
13632216Sbostic 	}
13732216Sbostic }
13832216Sbostic 
13932216Sbostic /*
14032227Sbostic  * read_ttys --
14132227Sbostic  *	read through ttys listed in the control file, decide if this
14232227Sbostic  *	tty can be used for games.
14332227Sbostic  */
14432227Sbostic static
14532227Sbostic read_ttys()
14632227Sbostic {
14732227Sbostic 	register char	*p_tty;
14832227Sbostic 	char	lbuf[BUFSIZ], f1[40], f2[40],
14932227Sbostic 		*ttyname(), *rindex();
15032227Sbostic 
15132227Sbostic 	gametty = ttyname(0);
15232227Sbostic 	if (p_tty = rindex(gametty, '/'))
15332227Sbostic 		++p_tty;
15432227Sbostic 	while (fgets(lbuf, sizeof(lbuf), cfp)) {
15532227Sbostic 		if (lignore(lbuf))
15632227Sbostic 			continue;
15732227Sbostic 		if (lcontrol(lbuf))
15832227Sbostic 			return;
15932227Sbostic 		if (sscanf(lbuf, "%s%s", f1, f2) != 2)
16032227Sbostic 			continue;
16132227Sbostic 		if (strcasecmp("badtty", f1))
16232227Sbostic 			continue;
16332227Sbostic 		if (!strcmp(gametty, f2) || p_tty && !strcmp(p_tty, f2)) {
16432227Sbostic 			fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty);
16532227Sbostic 			exit(0);
16632227Sbostic 		}
16732227Sbostic 	}
16832227Sbostic }
16932227Sbostic 
17032227Sbostic /*
17132216Sbostic  * read_games --
17232227Sbostic  *	read through games listed in the control file, decide if this
17332227Sbostic  *	game can be played now.
17432216Sbostic  */
17532216Sbostic static
17632227Sbostic read_games()
17732216Sbostic {
17832227Sbostic 	char	lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40];
17932216Sbostic 
18032227Sbostic 	while (fgets(lbuf, sizeof(lbuf), cfp)) {
18132227Sbostic 		if (lignore(lbuf))
18232216Sbostic 			continue;
18332227Sbostic 		if (lcontrol(lbuf))
18432227Sbostic 			return;
18532227Sbostic 		if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4)
18632227Sbostic 			break;
18732227Sbostic 		if (!strcmp(game, f1) || !strcasecmp("default", f1)) {
18832227Sbostic 			if (isdigit(*f2) && atoi(f2) < load()) {
18932227Sbostic 				fputs("dm: Sorry, the load average is too high right now.\n", stderr);
19032227Sbostic 				exit(0);
19132227Sbostic 			}
19232227Sbostic 			if (isdigit(*f3) && atoi(f3) <= users()) {
19332227Sbostic 				fputs("dm: Sorry, there are too many users logged on right now.\n", stderr);
19432227Sbostic 				exit(0);
19532227Sbostic 			}
196*32245Sbostic 			if (isdigit(*f4))
19732216Sbostic 				priority = atoi(f3);
19832227Sbostic 			return;
19932216Sbostic 		}
20032216Sbostic 	}
20132216Sbostic }
20232216Sbostic 
20332216Sbostic static struct	nlist nl[] = {
20432216Sbostic 	{ "_avenrun" },
20532216Sbostic #define	X_AVENRUN	0
20632216Sbostic 	{ "" },
20732216Sbostic };
20832216Sbostic 
20932216Sbostic /*
21032216Sbostic  * load --
21132216Sbostic  *	return 15 minute load average
21232216Sbostic  */
21332216Sbostic static double
21432216Sbostic load()
21532216Sbostic {
21632216Sbostic 	double	avenrun[3];
21732216Sbostic 	int	kmem;
21832216Sbostic 	long	lseek();
21932216Sbostic 
22032216Sbostic 	if (nlist("/vmunix", nl)) {
22132216Sbostic 		fputs("dm: nlist of /vmunix failed.\n", stderr);
22232216Sbostic 		exit(1);
22332216Sbostic 	}
22432216Sbostic 	if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) {
22532216Sbostic 		perror("dm: /dev/kmem");
22632216Sbostic 		exit(1);
22732216Sbostic 	}
22832216Sbostic 	(void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET);
22932216Sbostic 	(void)read(kmem, avenrun, sizeof(avenrun));
23032216Sbostic 	return(avenrun[2]);
23132216Sbostic }
23232216Sbostic 
23332216Sbostic /*
23432216Sbostic  * users --
23532216Sbostic  *	return current number of users
23632216Sbostic  */
23732216Sbostic static
23832216Sbostic users()
23932216Sbostic {
24032216Sbostic 	register int	nusers,
24132216Sbostic 			utmp;
24232216Sbostic 	struct utmp	buf;
24332216Sbostic 
24432216Sbostic 	if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) {
24532216Sbostic 		perror("dm: /etc/utmp");
24632216Sbostic 		exit(1);
24732216Sbostic 	}
24832216Sbostic 	for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
24932216Sbostic 		if (buf.ut_name[0] != '\0')
25032216Sbostic 			++nusers;
25132216Sbostic 	return(nusers);
25232216Sbostic }
25332216Sbostic 
25432216Sbostic /*
25532216Sbostic  * nogamefile --
25632216Sbostic  *	if the file NOGAMING exists, no games allowed.
25732216Sbostic  *	file may also contain a message for the user.
25832216Sbostic  */
25932216Sbostic static
26032216Sbostic nogamefile()
26132216Sbostic {
26232216Sbostic 	register int	fd, n;
26332216Sbostic 	char	buf[BUFSIZ];
26432216Sbostic 
26532216Sbostic 	if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) {
26632216Sbostic #define	MESG	"Sorry, no games right now.\n\n"
26732216Sbostic 		(void)write(2, MESG, sizeof(MESG) - 1);
26832216Sbostic 		while ((n = read(fd, buf, sizeof(buf))) > 0)
26932216Sbostic 			(void)write(2, buf, n);
27032216Sbostic 		exit(1);
27132216Sbostic 	}
27232216Sbostic }
27332216Sbostic 
27432216Sbostic /*
27532216Sbostic  * hour --
27632216Sbostic  *	print out the hour in human form
27732216Sbostic  */
27832227Sbostic static
27932216Sbostic hour(h)
28032216Sbostic 	int	h;
28132216Sbostic {
28232227Sbostic 	switch(h) {
28332227Sbostic 	case 0:
28432227Sbostic 		fputs("midnight", stderr);
28532227Sbostic 		break;
28632227Sbostic 	case 12:
28732227Sbostic 		fputs("noon", stderr);
28832227Sbostic 		break;
28932227Sbostic 	default:
29032227Sbostic 		if (h > 12)
29132227Sbostic 			fprintf(stderr, "%dpm", h - 12);
29232227Sbostic 		else
29332227Sbostic 			fprintf(stderr, "%dam", h);
29432227Sbostic 	}
29532216Sbostic }
29632216Sbostic 
29732216Sbostic #ifdef LOG
29832216Sbostic static
29932216Sbostic logfile()
30032216Sbostic {
30132216Sbostic 	struct passwd	*pw, *getpwuid();
30232216Sbostic 	FILE	*lp;
30332216Sbostic 	uid_t	uid;
30432216Sbostic 	int	lock_cnt;
30532227Sbostic 	char	*ctime();
30632216Sbostic 
30732216Sbostic 	if (lp = fopen(LOGFILE, "a")) {
30832216Sbostic 		for (lock_cnt = 0;; ++lock_cnt) {
30932216Sbostic 			if (!flock(fileno(lp), LOCK_EX))
31032216Sbostic 				break;
31132216Sbostic 			if (lock_cnt == 4) {
31232216Sbostic 				perror("dm: log lock");
31332216Sbostic 				(void)fclose(lp);
31432216Sbostic 				return;
31532216Sbostic 			}
31632216Sbostic 			sleep((u_int)1);
31732216Sbostic 		}
31832216Sbostic 		if (pw = getpwuid(uid = getuid()))
31932216Sbostic 			fputs(pw->pw_name, lp);
32032216Sbostic 		else
32132216Sbostic 			fprintf(lp, "%u", uid);
32232227Sbostic 		fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
32332216Sbostic 		(void)fclose(lp);
32432216Sbostic 		(void)flock(fileno(lp), LOCK_UN);
32532216Sbostic 	}
32632216Sbostic }
32732216Sbostic #endif
328