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