dm.c revision 1.13 1 1.13 jsm /* $NetBSD: dm.c,v 1.13 1999/09/19 18:13:41 jsm Exp $ */
2 1.4 cgd
3 1.1 cgd /*
4 1.4 cgd * Copyright (c) 1987, 1993
5 1.4 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.1 cgd * 3. All advertising materials mentioning features or use of this software
16 1.1 cgd * must display the following acknowledgement:
17 1.1 cgd * This product includes software developed by the University of
18 1.1 cgd * California, Berkeley and its contributors.
19 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
20 1.1 cgd * may be used to endorse or promote products derived from this software
21 1.1 cgd * without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 cgd * SUCH DAMAGE.
34 1.1 cgd */
35 1.1 cgd
36 1.7 lukem #include <sys/cdefs.h>
37 1.1 cgd #ifndef lint
38 1.7 lukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
39 1.7 lukem The Regents of the University of California. All rights reserved.\n");
40 1.1 cgd #endif /* not lint */
41 1.1 cgd
42 1.1 cgd #ifndef lint
43 1.4 cgd #if 0
44 1.4 cgd static char sccsid[] = "@(#)dm.c 8.1 (Berkeley) 5/31/93";
45 1.4 cgd #else
46 1.13 jsm __RCSID("$NetBSD: dm.c,v 1.13 1999/09/19 18:13:41 jsm Exp $");
47 1.4 cgd #endif
48 1.1 cgd #endif /* not lint */
49 1.1 cgd
50 1.1 cgd #include <sys/param.h>
51 1.1 cgd #include <sys/file.h>
52 1.1 cgd #include <sys/time.h>
53 1.1 cgd #include <sys/resource.h>
54 1.4 cgd
55 1.7 lukem #include <err.h>
56 1.4 cgd #include <ctype.h>
57 1.7 lukem #include <errno.h>
58 1.4 cgd #include <nlist.h>
59 1.1 cgd #include <pwd.h>
60 1.1 cgd #include <stdio.h>
61 1.7 lukem #include <stdlib.h>
62 1.2 mycroft #include <string.h>
63 1.4 cgd #include <time.h>
64 1.4 cgd #include <unistd.h>
65 1.4 cgd #include <utmp.h>
66 1.4 cgd
67 1.1 cgd #include "pathnames.h"
68 1.1 cgd
69 1.1 cgd static time_t now; /* current time value */
70 1.1 cgd static int priority = 0; /* priority game runs at */
71 1.1 cgd static char *game, /* requested game */
72 1.1 cgd *gametty; /* from tty? */
73 1.1 cgd
74 1.12 hubertf void c_day __P((const char *, const char *, const char *));
75 1.12 hubertf void c_game __P((const char *, const char *, const char *, const char *));
76 1.12 hubertf void c_tty __P((const char *));
77 1.7 lukem const char *hour __P((int));
78 1.7 lukem double load __P((void));
79 1.7 lukem int main __P((int, char *[]));
80 1.7 lukem void nogamefile __P((void));
81 1.11 hubertf void play __P((char **)) __attribute__((__noreturn__));
82 1.7 lukem void read_config __P((void));
83 1.7 lukem int users __P((void));
84 1.7 lukem
85 1.4 cgd int
86 1.1 cgd main(argc, argv)
87 1.1 cgd int argc;
88 1.4 cgd char *argv[];
89 1.1 cgd {
90 1.4 cgd char *cp;
91 1.1 cgd
92 1.1 cgd nogamefile();
93 1.7 lukem game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
94 1.1 cgd
95 1.1 cgd if (!strcmp(game, "dm"))
96 1.1 cgd exit(0);
97 1.1 cgd
98 1.1 cgd gametty = ttyname(0);
99 1.10 hubertf unsetenv("TZ");
100 1.1 cgd (void)time(&now);
101 1.1 cgd read_config();
102 1.1 cgd #ifdef LOG
103 1.1 cgd logfile();
104 1.1 cgd #endif
105 1.1 cgd play(argv);
106 1.1 cgd /*NOTREACHED*/
107 1.9 mrg return (0);
108 1.1 cgd }
109 1.1 cgd
110 1.1 cgd /*
111 1.1 cgd * play --
112 1.1 cgd * play the game
113 1.1 cgd */
114 1.7 lukem void
115 1.1 cgd play(args)
116 1.1 cgd char **args;
117 1.1 cgd {
118 1.2 mycroft char pbuf[MAXPATHLEN];
119 1.1 cgd
120 1.6 mrg (void)strncpy(pbuf, _PATH_HIDE, sizeof(pbuf) - 1);
121 1.6 mrg (void)strncpy(pbuf + sizeof(_PATH_HIDE) - 1, game,
122 1.6 mrg sizeof(pbuf) - sizeof(_PATH_HIDE) - 1);
123 1.6 mrg pbuf[sizeof(pbuf) - 1] = '\0';
124 1.1 cgd if (priority > 0) /* < 0 requires root */
125 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, priority);
126 1.1 cgd execv(pbuf, args);
127 1.7 lukem err(1, "%s", pbuf);
128 1.1 cgd }
129 1.1 cgd
130 1.1 cgd /*
131 1.1 cgd * read_config --
132 1.1 cgd * read through config file, looking for key words.
133 1.1 cgd */
134 1.7 lukem void
135 1.1 cgd read_config()
136 1.1 cgd {
137 1.1 cgd FILE *cfp;
138 1.1 cgd char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
139 1.1 cgd
140 1.1 cgd if (!(cfp = fopen(_PATH_CONFIG, "r")))
141 1.1 cgd return;
142 1.1 cgd while (fgets(lbuf, sizeof(lbuf), cfp))
143 1.9 mrg switch (*lbuf) {
144 1.1 cgd case 'b': /* badtty */
145 1.1 cgd if (sscanf(lbuf, "%s%s", f1, f2) != 2 ||
146 1.1 cgd strcasecmp(f1, "badtty"))
147 1.1 cgd break;
148 1.1 cgd c_tty(f2);
149 1.1 cgd break;
150 1.1 cgd case 'g': /* game */
151 1.1 cgd if (sscanf(lbuf, "%s%s%s%s%s",
152 1.1 cgd f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
153 1.1 cgd break;
154 1.1 cgd c_game(f2, f3, f4, f5);
155 1.1 cgd break;
156 1.1 cgd case 't': /* time */
157 1.1 cgd if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 ||
158 1.1 cgd strcasecmp(f1, "time"))
159 1.1 cgd break;
160 1.1 cgd c_day(f2, f3, f4);
161 1.1 cgd }
162 1.1 cgd (void)fclose(cfp);
163 1.1 cgd }
164 1.1 cgd
165 1.1 cgd /*
166 1.1 cgd * c_day --
167 1.1 cgd * if day is today, see if okay to play
168 1.1 cgd */
169 1.7 lukem void
170 1.1 cgd c_day(s_day, s_start, s_stop)
171 1.12 hubertf const char *s_day, *s_start, *s_stop;
172 1.1 cgd {
173 1.12 hubertf static const char *const days[] = {
174 1.1 cgd "sunday", "monday", "tuesday", "wednesday",
175 1.1 cgd "thursday", "friday", "saturday",
176 1.1 cgd };
177 1.1 cgd static struct tm *ct;
178 1.1 cgd int start, stop;
179 1.1 cgd
180 1.1 cgd if (!ct)
181 1.1 cgd ct = localtime(&now);
182 1.1 cgd if (strcasecmp(s_day, days[ct->tm_wday]))
183 1.1 cgd return;
184 1.1 cgd if (!isdigit(*s_start) || !isdigit(*s_stop))
185 1.1 cgd return;
186 1.1 cgd start = atoi(s_start);
187 1.1 cgd stop = atoi(s_stop);
188 1.13 jsm if (ct->tm_hour >= start && ct->tm_hour < stop) {
189 1.13 jsm if (start == 0 && stop == 24)
190 1.13 jsm errx(0, "Sorry, games are not available today.");
191 1.13 jsm else
192 1.13 jsm errx(0, "Sorry, games are not available from %s to %s today.",
193 1.13 jsm hour(start), hour(stop));
194 1.13 jsm }
195 1.1 cgd }
196 1.1 cgd
197 1.1 cgd /*
198 1.1 cgd * c_tty --
199 1.1 cgd * decide if this tty can be used for games.
200 1.1 cgd */
201 1.7 lukem void
202 1.1 cgd c_tty(tty)
203 1.12 hubertf const char *tty;
204 1.1 cgd {
205 1.1 cgd static int first = 1;
206 1.1 cgd static char *p_tty;
207 1.1 cgd
208 1.1 cgd if (first) {
209 1.7 lukem p_tty = strrchr(gametty, '/');
210 1.1 cgd first = 0;
211 1.1 cgd }
212 1.1 cgd
213 1.7 lukem if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
214 1.7 lukem errx(1, "Sorry, you may not play games on %s.", gametty);
215 1.1 cgd }
216 1.1 cgd
217 1.1 cgd /*
218 1.1 cgd * c_game --
219 1.1 cgd * see if game can be played now.
220 1.1 cgd */
221 1.7 lukem void
222 1.1 cgd c_game(s_game, s_load, s_users, s_priority)
223 1.12 hubertf const char *s_game, *s_load, *s_users, *s_priority;
224 1.1 cgd {
225 1.1 cgd static int found;
226 1.1 cgd
227 1.1 cgd if (found)
228 1.1 cgd return;
229 1.1 cgd if (strcmp(game, s_game) && strcasecmp("default", s_game))
230 1.1 cgd return;
231 1.1 cgd ++found;
232 1.7 lukem if (isdigit(*s_load) && atoi(s_load) < load())
233 1.7 lukem errx(0, "Sorry, the load average is too high right now.");
234 1.7 lukem if (isdigit(*s_users) && atoi(s_users) <= users())
235 1.7 lukem errx(0, "Sorry, there are too many users logged on right now.");
236 1.1 cgd if (isdigit(*s_priority))
237 1.1 cgd priority = atoi(s_priority);
238 1.1 cgd }
239 1.1 cgd
240 1.1 cgd /*
241 1.1 cgd * load --
242 1.1 cgd * return 15 minute load average
243 1.1 cgd */
244 1.1 cgd double
245 1.1 cgd load()
246 1.1 cgd {
247 1.1 cgd double avenrun[3];
248 1.1 cgd
249 1.7 lukem if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
250 1.7 lukem err(1, "getloadavg() failed.");
251 1.9 mrg return (avenrun[2]);
252 1.1 cgd }
253 1.1 cgd
254 1.1 cgd /*
255 1.1 cgd * users --
256 1.1 cgd * return current number of users
257 1.1 cgd * todo: check idle time; if idle more than X minutes, don't
258 1.1 cgd * count them.
259 1.1 cgd */
260 1.7 lukem int
261 1.1 cgd users()
262 1.1 cgd {
263 1.1 cgd
264 1.7 lukem int nusers, utmp;
265 1.1 cgd struct utmp buf;
266 1.1 cgd
267 1.7 lukem if ((utmp = open(_PATH_UTMP, O_RDONLY, 0)) < 0)
268 1.7 lukem err(1, "%s", _PATH_UTMP);
269 1.1 cgd for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
270 1.1 cgd if (buf.ut_name[0] != '\0')
271 1.1 cgd ++nusers;
272 1.9 mrg return (nusers);
273 1.1 cgd }
274 1.1 cgd
275 1.7 lukem void
276 1.1 cgd nogamefile()
277 1.1 cgd {
278 1.7 lukem int fd, n;
279 1.1 cgd char buf[BUFSIZ];
280 1.1 cgd
281 1.1 cgd if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
282 1.1 cgd #define MESG "Sorry, no games right now.\n\n"
283 1.1 cgd (void)write(2, MESG, sizeof(MESG) - 1);
284 1.1 cgd while ((n = read(fd, buf, sizeof(buf))) > 0)
285 1.1 cgd (void)write(2, buf, n);
286 1.1 cgd exit(1);
287 1.1 cgd }
288 1.1 cgd }
289 1.1 cgd
290 1.1 cgd /*
291 1.1 cgd * hour --
292 1.1 cgd * print out the hour in human form
293 1.1 cgd */
294 1.7 lukem const char *
295 1.1 cgd hour(h)
296 1.1 cgd int h;
297 1.1 cgd {
298 1.12 hubertf static const char *const hours[] = {
299 1.7 lukem "midnight", "1am", "2am", "3am", "4am", "5am",
300 1.7 lukem "6am", "7am", "8am", "9am", "10am", "11am",
301 1.7 lukem "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
302 1.13 jsm "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
303 1.7 lukem
304 1.13 jsm if (h < 0 || h > 24)
305 1.9 mrg return ("BAD TIME");
306 1.7 lukem else
307 1.9 mrg return (hours[h]);
308 1.1 cgd }
309 1.1 cgd
310 1.1 cgd #ifdef LOG
311 1.1 cgd /*
312 1.1 cgd * logfile --
313 1.1 cgd * log play of game
314 1.1 cgd */
315 1.1 cgd logfile()
316 1.1 cgd {
317 1.4 cgd struct passwd *pw;
318 1.1 cgd FILE *lp;
319 1.1 cgd uid_t uid;
320 1.1 cgd int lock_cnt;
321 1.1 cgd
322 1.1 cgd if (lp = fopen(_PATH_LOG, "a")) {
323 1.1 cgd for (lock_cnt = 0;; ++lock_cnt) {
324 1.1 cgd if (!flock(fileno(lp), LOCK_EX))
325 1.1 cgd break;
326 1.1 cgd if (lock_cnt == 4) {
327 1.7 lukem warnx("log lock");
328 1.1 cgd (void)fclose(lp);
329 1.1 cgd return;
330 1.1 cgd }
331 1.1 cgd sleep((u_int)1);
332 1.1 cgd }
333 1.1 cgd if (pw = getpwuid(uid = getuid()))
334 1.1 cgd fputs(pw->pw_name, lp);
335 1.1 cgd else
336 1.1 cgd fprintf(lp, "%u", uid);
337 1.1 cgd fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
338 1.1 cgd (void)fclose(lp);
339 1.1 cgd (void)flock(fileno(lp), LOCK_UN);
340 1.1 cgd }
341 1.1 cgd }
342 1.1 cgd #endif /* LOG */
343