xref: /csrg-svn/games/dm/dm.c (revision 32216)
1*32216Sbostic /*
2*32216Sbostic  * Copyright (c) 1987 Regents of the University of California.
3*32216Sbostic  * All rights reserved.  The Berkeley software License Agreement
4*32216Sbostic  * specifies the terms and conditions for redistribution.
5*32216Sbostic  */
6*32216Sbostic 
7*32216Sbostic #ifndef lint
8*32216Sbostic char copyright[] =
9*32216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\
10*32216Sbostic  All rights reserved.\n";
11*32216Sbostic #endif not lint
12*32216Sbostic 
13*32216Sbostic #ifndef lint
14*32216Sbostic static char sccsid[] = "@(#)dm.c	5.1 (Berkeley) 09/18/87";
15*32216Sbostic #endif not lint
16*32216Sbostic 
17*32216Sbostic #include <sys/param.h>
18*32216Sbostic #include <sys/file.h>
19*32216Sbostic #include <sys/time.h>
20*32216Sbostic #include <sys/resource.h>
21*32216Sbostic #include <pwd.h>
22*32216Sbostic #include <utmp.h>
23*32216Sbostic #include <nlist.h>
24*32216Sbostic #include <stdio.h>
25*32216Sbostic #include <ctype.h>
26*32216Sbostic 
27*32216Sbostic #define	LOG			/* if want game usage logged */
28*32216Sbostic 
29*32216Sbostic #define	GAMEHIDE	"/usr/games/hide"
30*32216Sbostic #define	NOGAMING	"/etc/nogames"
31*32216Sbostic #define	CONTROL		"/usr/games/game.control"
32*32216Sbostic #ifdef LOG
33*32216Sbostic #define	LOGFILE		"/usr/adm/gamelog"
34*32216Sbostic #endif
35*32216Sbostic 
36*32216Sbostic static struct tm	*ct;		/* current time structure */
37*32216Sbostic static time_t	now;			/* current time value */
38*32216Sbostic static double	maxload = -1;		/* max load for game */
39*32216Sbostic static int	maxusers = -1;		/* max users for game */
40*32216Sbostic 		priority = 0;		/* priority game runs at */
41*32216Sbostic static char	*game;			/* requested game */
42*32216Sbostic 
43*32216Sbostic typedef struct dow {
44*32216Sbostic 	char	*day;
45*32216Sbostic 	int	start, stop;
46*32216Sbostic } DOW;
47*32216Sbostic 
48*32216Sbostic static DOW	days[] = {
49*32216Sbostic 	"sunday",	25, -1,
50*32216Sbostic 	"monday",	25, -1,
51*32216Sbostic 	"tuesday",	25, -1,
52*32216Sbostic 	"wednesday",	25, -1,
53*32216Sbostic 	"thursday",	25, -1,
54*32216Sbostic 	"friday",	25, -1,
55*32216Sbostic 	"saturday",	25, -1,
56*32216Sbostic 	0,		0,  0,
57*32216Sbostic };
58*32216Sbostic 
59*32216Sbostic main(argc, argv)
60*32216Sbostic 	int	argc;
61*32216Sbostic 	char	**argv;
62*32216Sbostic {
63*32216Sbostic 	FILE	*fp;
64*32216Sbostic 	char	*C, *hour(), *rindex();
65*32216Sbostic 	struct tm	*localtime();
66*32216Sbostic 	time_t	time();
67*32216Sbostic 	double	load();
68*32216Sbostic 
69*32216Sbostic 	nogamefile();
70*32216Sbostic 
71*32216Sbostic 	if (argc == 1) {
72*32216Sbostic 		fputs("dm: game\n", stderr);
73*32216Sbostic 		exit(1);
74*32216Sbostic 	}
75*32216Sbostic 
76*32216Sbostic 	if (!(fp = fopen(CONTROL, "r"))) {
77*32216Sbostic 		fprintf(stderr, "dm: unable to read %s.\n", CONTROL);
78*32216Sbostic 		exit(1);
79*32216Sbostic 	}
80*32216Sbostic 
81*32216Sbostic 	read_days(fp);
82*32216Sbostic 	(void)time(&now);
83*32216Sbostic 	ct = localtime(&now);
84*32216Sbostic 	if (ct->tm_hour >= days[ct->tm_wday].start && ct->tm_hour <= days[ct->tm_wday].stop) {
85*32216Sbostic 		fprintf(stderr, "dm: Sorry, games are only available from %s to %s today.\n", hour(days[ct->tm_wday].start), hour(days[ct->tm_wday].stop));
86*32216Sbostic 		exit(0);
87*32216Sbostic 	}
88*32216Sbostic 
89*32216Sbostic 	++argv;
90*32216Sbostic 	game = (C = rindex(*argv, '/')) ? ++C : *argv;
91*32216Sbostic 
92*32216Sbostic 	read_games(fp);
93*32216Sbostic 	if (maxusers >= 0 && maxusers <= users()) {
94*32216Sbostic 		fputs("dm: Sorry, there are too many users logged on right now.\n", stderr);
95*32216Sbostic 		exit(0);
96*32216Sbostic 	}
97*32216Sbostic 	if (maxload >= 0 && maxload < load()) {
98*32216Sbostic 		fputs("dm: Sorry, the load average is too high right now.\n", stderr);
99*32216Sbostic 		exit(0);
100*32216Sbostic 	}
101*32216Sbostic 	(void)fclose(fp);
102*32216Sbostic 
103*32216Sbostic #ifdef LOG
104*32216Sbostic 	logfile();
105*32216Sbostic #endif
106*32216Sbostic 	play(argv);
107*32216Sbostic }
108*32216Sbostic 
109*32216Sbostic /*
110*32216Sbostic  * play --
111*32216Sbostic  *	play the game
112*32216Sbostic  */
113*32216Sbostic static
114*32216Sbostic play(args)
115*32216Sbostic 	char	**args;
116*32216Sbostic {
117*32216Sbostic 	uid_t	uid;
118*32216Sbostic 	gid_t	gid;
119*32216Sbostic 
120*32216Sbostic 	if (chdir(GAMEHIDE)) {
121*32216Sbostic 		perror("dm: chdir");
122*32216Sbostic 		exit(1);
123*32216Sbostic 	}
124*32216Sbostic 	if (priority && setpriority(PRIO_PROCESS, 0, priority) < 0)
125*32216Sbostic 		fputs("dm: unable to set priority!\n", stderr);
126*32216Sbostic 	uid = getuid();
127*32216Sbostic 	setreuid(uid, uid);
128*32216Sbostic 	gid = getgid();
129*32216Sbostic 	setregid(gid, gid);
130*32216Sbostic 	execv(game, args);
131*32216Sbostic 	fprintf(stderr, "dm: can't find %s.\n", game);
132*32216Sbostic 	exit(1);
133*32216Sbostic }
134*32216Sbostic 
135*32216Sbostic /*
136*32216Sbostic  * read_days --
137*32216Sbostic  *	read through days listed in the control file
138*32216Sbostic  */
139*32216Sbostic static
140*32216Sbostic read_days(fp)
141*32216Sbostic 	register FILE	*fp;
142*32216Sbostic {
143*32216Sbostic 	register DOW	*dp;
144*32216Sbostic 	char	lbuf[BUFSIZ], f1[20], f2[20], f3[20];
145*32216Sbostic 
146*32216Sbostic 	while (fgets(lbuf, sizeof(lbuf), fp)) {
147*32216Sbostic 		if (lbuf[0] == '\n' || lbuf[0] == '#')
148*32216Sbostic 			continue;
149*32216Sbostic 		/* special line separates days from game names */
150*32216Sbostic 		if (lbuf[0] == '%' && lbuf[1] == '%')
151*32216Sbostic 			return;
152*32216Sbostic 		if (sscanf(lbuf, "%s%s%s\n", f1, f2, f3) != 3)
153*32216Sbostic 			continue;
154*32216Sbostic 		for (dp = days; dp->day; ++dp)
155*32216Sbostic 			if (dp->start <= 0 && !strcasecmp(dp->day, f1)) {
156*32216Sbostic 				if (isdigit(*f2))
157*32216Sbostic 					dp->start = atoi(f2);
158*32216Sbostic 				if (isdigit(*f3))
159*32216Sbostic 					dp->stop = atoi(f3);
160*32216Sbostic 				break;
161*32216Sbostic 			}
162*32216Sbostic 	}
163*32216Sbostic }
164*32216Sbostic 
165*32216Sbostic /*
166*32216Sbostic  * read_games --
167*32216Sbostic  *	read through games listed in the control file
168*32216Sbostic  */
169*32216Sbostic static
170*32216Sbostic read_games(fp)
171*32216Sbostic 	register FILE	*fp;
172*32216Sbostic {
173*32216Sbostic 	register char	*C;
174*32216Sbostic 	char	lbuf[BUFSIZ], f1[20], f2[20], f3[20];
175*32216Sbostic 	double	atof();
176*32216Sbostic 
177*32216Sbostic 	while (fgets(lbuf, sizeof(lbuf), fp)) {
178*32216Sbostic 		if (lbuf[0] == '\n' || lbuf[0] == '#')
179*32216Sbostic 			continue;
180*32216Sbostic 		for (C = lbuf; *C && !isspace(*C); ++C);
181*32216Sbostic 		*C = '\0';
182*32216Sbostic 		if (!strcmp(game, lbuf) || !strcasecmp("default", lbuf)) {
183*32216Sbostic 			if (sscanf(++C, "%s%s%s\n", f1, f2, f3) != 3)
184*32216Sbostic 				break;
185*32216Sbostic 			if (isdigit(*f1))
186*32216Sbostic 				maxload = atof(f1);
187*32216Sbostic 			if (isdigit(*f2))
188*32216Sbostic 				maxusers = atoi(f2);
189*32216Sbostic 			if (isdigit(*f3) || *f3 == '-' || *f3 == '+')
190*32216Sbostic 				priority = atoi(f3);
191*32216Sbostic 			break;
192*32216Sbostic 		}
193*32216Sbostic 	}
194*32216Sbostic }
195*32216Sbostic 
196*32216Sbostic static struct	nlist nl[] = {
197*32216Sbostic 	{ "_avenrun" },
198*32216Sbostic #define	X_AVENRUN	0
199*32216Sbostic 	{ "" },
200*32216Sbostic };
201*32216Sbostic 
202*32216Sbostic /*
203*32216Sbostic  * load --
204*32216Sbostic  *	return 15 minute load average
205*32216Sbostic  */
206*32216Sbostic static double
207*32216Sbostic load()
208*32216Sbostic {
209*32216Sbostic 	double	avenrun[3];
210*32216Sbostic 	int	kmem;
211*32216Sbostic 	long	lseek();
212*32216Sbostic 
213*32216Sbostic 	if (nlist("/vmunix", nl)) {
214*32216Sbostic 		fputs("dm: nlist of /vmunix failed.\n", stderr);
215*32216Sbostic 		exit(1);
216*32216Sbostic 	}
217*32216Sbostic 	if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) {
218*32216Sbostic 		perror("dm: /dev/kmem");
219*32216Sbostic 		exit(1);
220*32216Sbostic 	}
221*32216Sbostic 	(void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET);
222*32216Sbostic 	(void)read(kmem, avenrun, sizeof(avenrun));
223*32216Sbostic 	return(avenrun[2]);
224*32216Sbostic }
225*32216Sbostic 
226*32216Sbostic /*
227*32216Sbostic  * users --
228*32216Sbostic  *	return current number of users
229*32216Sbostic  */
230*32216Sbostic static
231*32216Sbostic users()
232*32216Sbostic {
233*32216Sbostic 	register int	nusers,
234*32216Sbostic 			utmp;
235*32216Sbostic 	struct utmp	buf;
236*32216Sbostic 
237*32216Sbostic 	if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) {
238*32216Sbostic 		perror("dm: /etc/utmp");
239*32216Sbostic 		exit(1);
240*32216Sbostic 	}
241*32216Sbostic 	for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
242*32216Sbostic 		if (buf.ut_name[0] != '\0')
243*32216Sbostic 			++nusers;
244*32216Sbostic 	return(nusers);
245*32216Sbostic }
246*32216Sbostic 
247*32216Sbostic /*
248*32216Sbostic  * nogamefile --
249*32216Sbostic  *	if the file NOGAMING exists, no games allowed.
250*32216Sbostic  *	file may also contain a message for the user.
251*32216Sbostic  */
252*32216Sbostic static
253*32216Sbostic nogamefile()
254*32216Sbostic {
255*32216Sbostic 	register int	fd, n;
256*32216Sbostic 	char	buf[BUFSIZ];
257*32216Sbostic 
258*32216Sbostic 	if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) {
259*32216Sbostic #define	MESG	"Sorry, no games right now.\n\n"
260*32216Sbostic 		(void)write(2, MESG, sizeof(MESG) - 1);
261*32216Sbostic 		while ((n = read(fd, buf, sizeof(buf))) > 0)
262*32216Sbostic 			(void)write(2, buf, n);
263*32216Sbostic 		exit(1);
264*32216Sbostic 	}
265*32216Sbostic }
266*32216Sbostic 
267*32216Sbostic /*
268*32216Sbostic  * hour --
269*32216Sbostic  *	print out the hour in human form
270*32216Sbostic  */
271*32216Sbostic static char *
272*32216Sbostic hour(h)
273*32216Sbostic 	int	h;
274*32216Sbostic {
275*32216Sbostic 	static char	buf[20];
276*32216Sbostic 
277*32216Sbostic 	if (!h)
278*32216Sbostic 		return("midnight");
279*32216Sbostic 	if (h == 12)
280*32216Sbostic 		return("noon");
281*32216Sbostic 	if (h < 12)
282*32216Sbostic 		(void)sprintf(buf, "%d pm", h - 12);
283*32216Sbostic 	else
284*32216Sbostic 		(void)sprintf(buf, "%d am", h);
285*32216Sbostic 	return(buf);
286*32216Sbostic }
287*32216Sbostic 
288*32216Sbostic #ifdef LOG
289*32216Sbostic static
290*32216Sbostic logfile()
291*32216Sbostic {
292*32216Sbostic 	struct passwd	*pw, *getpwuid();
293*32216Sbostic 	FILE	*lp;
294*32216Sbostic 	uid_t	uid;
295*32216Sbostic 	int	lock_cnt;
296*32216Sbostic 	char	*ctime(), *ttyname();
297*32216Sbostic 
298*32216Sbostic 	if (lp = fopen(LOGFILE, "a")) {
299*32216Sbostic 		for (lock_cnt = 0;; ++lock_cnt) {
300*32216Sbostic 			if (!flock(fileno(lp), LOCK_EX))
301*32216Sbostic 				break;
302*32216Sbostic 			if (lock_cnt == 4) {
303*32216Sbostic 				perror("dm: log lock");
304*32216Sbostic 				(void)fclose(lp);
305*32216Sbostic 				return;
306*32216Sbostic 			}
307*32216Sbostic 			sleep((u_int)1);
308*32216Sbostic 		}
309*32216Sbostic 		if (pw = getpwuid(uid = getuid()))
310*32216Sbostic 			fputs(pw->pw_name, lp);
311*32216Sbostic 		else
312*32216Sbostic 			fprintf(lp, "%u", uid);
313*32216Sbostic 		fprintf(lp, "\t%s\t%s\t%s", game, ttyname(0), ctime(&now));
314*32216Sbostic 		(void)fclose(lp);
315*32216Sbostic 		(void)flock(fileno(lp), LOCK_UN);
316*32216Sbostic 	}
317*32216Sbostic }
318*32216Sbostic #endif
319