xref: /original-bsd/games/dm/dm.c (revision fac09079)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1987 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)dm.c	5.15 (Berkeley) 06/01/90";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/file.h>
20 #include <sys/time.h>
21 #include <sys/resource.h>
22 #include <pwd.h>
23 #include <utmp.h>
24 #include <nlist.h>
25 #include <stdio.h>
26 #include <ctype.h>
27 #include "pathnames.h"
28 
29 extern int errno;
30 static time_t	now;			/* current time value */
31 static int	priority = 0;		/* priority game runs at */
32 static char	*game,			/* requested game */
33 		*gametty;		/* from tty? */
34 
35 /*ARGSUSED*/
36 main(argc, argv)
37 	int argc;
38 	char **argv;
39 {
40 	char *cp, *rindex(), *ttyname();
41 	time_t time();
42 
43 	nogamefile();
44 	game = (cp = rindex(*argv, '/')) ? ++cp : *argv;
45 
46 	if (!strcmp(game, "dm"))
47 		exit(0);
48 
49 	gametty = ttyname(0);
50 	(void)time(&now);
51 	read_config();
52 #ifdef LOG
53 	logfile();
54 #endif
55 	play(argv);
56 	/*NOTREACHED*/
57 }
58 
59 /*
60  * play --
61  *	play the game
62  */
63 static
64 play(args)
65 	char **args;
66 {
67 	char pbuf[MAXPATHLEN], *strcpy(), *strerror();
68 
69 	(void)strcpy(pbuf, _PATH_HIDE);
70 	(void)strcpy(pbuf + sizeof(_PATH_HIDE) - 1, game);
71 	if (priority > 0)	/* < 0 requires root */
72 		(void)setpriority(PRIO_PROCESS, 0, priority);
73 	setgid(getgid());	/* we run setgid kmem; lose it */
74 	execv(pbuf, args);
75 	(void)fprintf(stderr, "dm: %s: %s\n", pbuf, strerror(errno));
76 	exit(1);
77 }
78 
79 /*
80  * read_config --
81  *	read through config file, looking for key words.
82  */
83 static
84 read_config()
85 {
86 	FILE *cfp;
87 	char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
88 
89 	if (!(cfp = fopen(_PATH_CONFIG, "r")))
90 		return;
91 	while (fgets(lbuf, sizeof(lbuf), cfp))
92 		switch(*lbuf) {
93 		case 'b':		/* badtty */
94 			if (sscanf(lbuf, "%s%s", f1, f2) != 2 ||
95 			    strcasecmp(f1, "badtty"))
96 				break;
97 			c_tty(f2);
98 			break;
99 		case 'g':		/* game */
100 			if (sscanf(lbuf, "%s%s%s%s%s",
101 			    f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
102 				break;
103 			c_game(f2, f3, f4, f5);
104 			break;
105 		case 't':		/* time */
106 			if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 ||
107 			    strcasecmp(f1, "time"))
108 				break;
109 			c_day(f2, f3, f4);
110 		}
111 	(void)fclose(cfp);
112 }
113 
114 /*
115  * c_day --
116  *	if day is today, see if okay to play
117  */
118 static
119 c_day(s_day, s_start, s_stop)
120 	char *s_day, *s_start, *s_stop;
121 {
122 	static char *days[] = {
123 		"sunday", "monday", "tuesday", "wednesday",
124 		"thursday", "friday", "saturday",
125 	};
126 	static struct tm *ct;
127 	int start, stop;
128 
129 	if (!ct)
130 		ct = localtime(&now);
131 	if (strcasecmp(s_day, days[ct->tm_wday]))
132 		return;
133 	if (!isdigit(*s_start) || !isdigit(*s_stop))
134 		return;
135 	start = atoi(s_start);
136 	stop = atoi(s_stop);
137 	if (ct->tm_hour >= start && ct->tm_hour < stop) {
138 		fputs("dm: Sorry, games are not available from ", stderr);
139 		hour(start);
140 		fputs(" to ", stderr);
141 		hour(stop);
142 		fputs(" today.\n", stderr);
143 		exit(0);
144 	}
145 }
146 
147 /*
148  * c_tty --
149  *	decide if this tty can be used for games.
150  */
151 static
152 c_tty(tty)
153 	char *tty;
154 {
155 	static int first = 1;
156 	static char *p_tty;
157 	char *rindex();
158 
159 	if (first) {
160 		p_tty = rindex(gametty, '/');
161 		first = 0;
162 	}
163 
164 	if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) {
165 		fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty);
166 		exit(0);
167 	}
168 }
169 
170 /*
171  * c_game --
172  *	see if game can be played now.
173  */
174 static
175 c_game(s_game, s_load, s_users, s_priority)
176 	char *s_game, *s_load, *s_users, *s_priority;
177 {
178 	static int found;
179 	double load();
180 
181 	if (found)
182 		return;
183 	if (strcmp(game, s_game) && strcasecmp("default", s_game))
184 		return;
185 	++found;
186 	if (isdigit(*s_load) && atoi(s_load) < load()) {
187 		fputs("dm: Sorry, the load average is too high right now.\n", stderr);
188 		exit(0);
189 	}
190 	if (isdigit(*s_users) && atoi(s_users) <= users()) {
191 		fputs("dm: Sorry, there are too many users logged on right now.\n", stderr);
192 		exit(0);
193 	}
194 	if (isdigit(*s_priority))
195 		priority = atoi(s_priority);
196 }
197 
198 /*
199  * load --
200  *	return 15 minute load average
201  */
202 static double
203 load()
204 {
205 	double avenrun[3];
206 
207 	if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0) {
208 		fputs("dm: getloadavg() failed.\n", stderr);
209 		exit(1);
210 	}
211 	return(avenrun[2]);
212 }
213 
214 /*
215  * users --
216  *	return current number of users
217  *	todo: check idle time; if idle more than X minutes, don't
218  *	count them.
219  */
220 static
221 users()
222 {
223 
224 	register int nusers, utmp;
225 	struct utmp buf;
226 
227 	if ((utmp = open(_PATH_UTMP, O_RDONLY, 0)) < 0) {
228 		(void)fprintf(stderr, "dm: %s: %s\n",
229 		    _PATH_UTMP, strerror(errno));
230 		exit(1);
231 	}
232 	for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
233 		if (buf.ut_name[0] != '\0')
234 			++nusers;
235 	return(nusers);
236 }
237 
238 static
239 nogamefile()
240 {
241 	register int fd, n;
242 	char buf[BUFSIZ];
243 
244 	if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
245 #define	MESG	"Sorry, no games right now.\n\n"
246 		(void)write(2, MESG, sizeof(MESG) - 1);
247 		while ((n = read(fd, buf, sizeof(buf))) > 0)
248 			(void)write(2, buf, n);
249 		exit(1);
250 	}
251 }
252 
253 /*
254  * hour --
255  *	print out the hour in human form
256  */
257 static
258 hour(h)
259 	int h;
260 {
261 	switch(h) {
262 	case 0:
263 		fputs("midnight", stderr);
264 		break;
265 	case 12:
266 		fputs("noon", stderr);
267 		break;
268 	default:
269 		if (h > 12)
270 			fprintf(stderr, "%dpm", h - 12);
271 		else
272 			fprintf(stderr, "%dam", h);
273 	}
274 }
275 
276 #ifdef LOG
277 /*
278  * logfile --
279  *	log play of game
280  */
281 static
282 logfile()
283 {
284 	struct passwd *pw, *getpwuid();
285 	FILE *lp;
286 	uid_t uid;
287 	int lock_cnt;
288 	char *ctime();
289 
290 	if (lp = fopen(_PATH_LOG, "a")) {
291 		for (lock_cnt = 0;; ++lock_cnt) {
292 			if (!flock(fileno(lp), LOCK_EX))
293 				break;
294 			if (lock_cnt == 4) {
295 				perror("dm: log lock");
296 				(void)fclose(lp);
297 				return;
298 			}
299 			sleep((u_int)1);
300 		}
301 		if (pw = getpwuid(uid = getuid()))
302 			fputs(pw->pw_name, lp);
303 		else
304 			fprintf(lp, "%u", uid);
305 		fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
306 		(void)fclose(lp);
307 		(void)flock(fileno(lp), LOCK_UN);
308 	}
309 }
310 #endif /* LOG */
311