dm.c revision 1.14 1 1.14 jsm /* $NetBSD: dm.c,v 1.14 1999/09/22 18:54:03 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.14 jsm __RCSID("$NetBSD: dm.c,v 1.14 1999/09/22 18:54:03 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.1 cgd #include <pwd.h>
59 1.1 cgd #include <stdio.h>
60 1.7 lukem #include <stdlib.h>
61 1.2 mycroft #include <string.h>
62 1.4 cgd #include <time.h>
63 1.4 cgd #include <unistd.h>
64 1.4 cgd #include <utmp.h>
65 1.4 cgd
66 1.1 cgd #include "pathnames.h"
67 1.1 cgd
68 1.1 cgd static time_t now; /* current time value */
69 1.1 cgd static int priority = 0; /* priority game runs at */
70 1.1 cgd static char *game, /* requested game */
71 1.1 cgd *gametty; /* from tty? */
72 1.1 cgd
73 1.12 hubertf void c_day __P((const char *, const char *, const char *));
74 1.12 hubertf void c_game __P((const char *, const char *, const char *, const char *));
75 1.12 hubertf void c_tty __P((const char *));
76 1.7 lukem const char *hour __P((int));
77 1.7 lukem double load __P((void));
78 1.7 lukem int main __P((int, char *[]));
79 1.7 lukem void nogamefile __P((void));
80 1.11 hubertf void play __P((char **)) __attribute__((__noreturn__));
81 1.7 lukem void read_config __P((void));
82 1.7 lukem int users __P((void));
83 1.7 lukem
84 1.4 cgd int
85 1.1 cgd main(argc, argv)
86 1.1 cgd int argc;
87 1.4 cgd char *argv[];
88 1.1 cgd {
89 1.4 cgd char *cp;
90 1.1 cgd
91 1.1 cgd nogamefile();
92 1.7 lukem game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
93 1.1 cgd
94 1.1 cgd if (!strcmp(game, "dm"))
95 1.1 cgd exit(0);
96 1.1 cgd
97 1.1 cgd gametty = ttyname(0);
98 1.10 hubertf unsetenv("TZ");
99 1.1 cgd (void)time(&now);
100 1.1 cgd read_config();
101 1.1 cgd #ifdef LOG
102 1.1 cgd logfile();
103 1.1 cgd #endif
104 1.1 cgd play(argv);
105 1.1 cgd /*NOTREACHED*/
106 1.9 mrg return (0);
107 1.1 cgd }
108 1.1 cgd
109 1.1 cgd /*
110 1.1 cgd * play --
111 1.1 cgd * play the game
112 1.1 cgd */
113 1.7 lukem void
114 1.1 cgd play(args)
115 1.1 cgd char **args;
116 1.1 cgd {
117 1.2 mycroft char pbuf[MAXPATHLEN];
118 1.1 cgd
119 1.6 mrg (void)strncpy(pbuf, _PATH_HIDE, sizeof(pbuf) - 1);
120 1.6 mrg (void)strncpy(pbuf + sizeof(_PATH_HIDE) - 1, game,
121 1.6 mrg sizeof(pbuf) - sizeof(_PATH_HIDE) - 1);
122 1.6 mrg pbuf[sizeof(pbuf) - 1] = '\0';
123 1.1 cgd if (priority > 0) /* < 0 requires root */
124 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, priority);
125 1.1 cgd execv(pbuf, args);
126 1.7 lukem err(1, "%s", pbuf);
127 1.1 cgd }
128 1.1 cgd
129 1.1 cgd /*
130 1.1 cgd * read_config --
131 1.1 cgd * read through config file, looking for key words.
132 1.1 cgd */
133 1.7 lukem void
134 1.1 cgd read_config()
135 1.1 cgd {
136 1.1 cgd FILE *cfp;
137 1.1 cgd char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
138 1.1 cgd
139 1.1 cgd if (!(cfp = fopen(_PATH_CONFIG, "r")))
140 1.1 cgd return;
141 1.1 cgd while (fgets(lbuf, sizeof(lbuf), cfp))
142 1.9 mrg switch (*lbuf) {
143 1.1 cgd case 'b': /* badtty */
144 1.1 cgd if (sscanf(lbuf, "%s%s", f1, f2) != 2 ||
145 1.1 cgd strcasecmp(f1, "badtty"))
146 1.1 cgd break;
147 1.1 cgd c_tty(f2);
148 1.1 cgd break;
149 1.1 cgd case 'g': /* game */
150 1.1 cgd if (sscanf(lbuf, "%s%s%s%s%s",
151 1.1 cgd f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
152 1.1 cgd break;
153 1.1 cgd c_game(f2, f3, f4, f5);
154 1.1 cgd break;
155 1.1 cgd case 't': /* time */
156 1.1 cgd if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 ||
157 1.1 cgd strcasecmp(f1, "time"))
158 1.1 cgd break;
159 1.1 cgd c_day(f2, f3, f4);
160 1.1 cgd }
161 1.1 cgd (void)fclose(cfp);
162 1.1 cgd }
163 1.1 cgd
164 1.1 cgd /*
165 1.1 cgd * c_day --
166 1.1 cgd * if day is today, see if okay to play
167 1.1 cgd */
168 1.7 lukem void
169 1.1 cgd c_day(s_day, s_start, s_stop)
170 1.12 hubertf const char *s_day, *s_start, *s_stop;
171 1.1 cgd {
172 1.12 hubertf static const char *const days[] = {
173 1.1 cgd "sunday", "monday", "tuesday", "wednesday",
174 1.1 cgd "thursday", "friday", "saturday",
175 1.1 cgd };
176 1.1 cgd static struct tm *ct;
177 1.1 cgd int start, stop;
178 1.1 cgd
179 1.1 cgd if (!ct)
180 1.1 cgd ct = localtime(&now);
181 1.1 cgd if (strcasecmp(s_day, days[ct->tm_wday]))
182 1.1 cgd return;
183 1.1 cgd if (!isdigit(*s_start) || !isdigit(*s_stop))
184 1.1 cgd return;
185 1.1 cgd start = atoi(s_start);
186 1.1 cgd stop = atoi(s_stop);
187 1.13 jsm if (ct->tm_hour >= start && ct->tm_hour < stop) {
188 1.13 jsm if (start == 0 && stop == 24)
189 1.13 jsm errx(0, "Sorry, games are not available today.");
190 1.13 jsm else
191 1.13 jsm errx(0, "Sorry, games are not available from %s to %s today.",
192 1.13 jsm hour(start), hour(stop));
193 1.13 jsm }
194 1.1 cgd }
195 1.1 cgd
196 1.1 cgd /*
197 1.1 cgd * c_tty --
198 1.1 cgd * decide if this tty can be used for games.
199 1.1 cgd */
200 1.7 lukem void
201 1.1 cgd c_tty(tty)
202 1.12 hubertf const char *tty;
203 1.1 cgd {
204 1.1 cgd static int first = 1;
205 1.1 cgd static char *p_tty;
206 1.1 cgd
207 1.1 cgd if (first) {
208 1.7 lukem p_tty = strrchr(gametty, '/');
209 1.1 cgd first = 0;
210 1.1 cgd }
211 1.1 cgd
212 1.7 lukem if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
213 1.7 lukem errx(1, "Sorry, you may not play games on %s.", gametty);
214 1.1 cgd }
215 1.1 cgd
216 1.1 cgd /*
217 1.1 cgd * c_game --
218 1.1 cgd * see if game can be played now.
219 1.1 cgd */
220 1.7 lukem void
221 1.1 cgd c_game(s_game, s_load, s_users, s_priority)
222 1.12 hubertf const char *s_game, *s_load, *s_users, *s_priority;
223 1.1 cgd {
224 1.1 cgd static int found;
225 1.1 cgd
226 1.1 cgd if (found)
227 1.1 cgd return;
228 1.1 cgd if (strcmp(game, s_game) && strcasecmp("default", s_game))
229 1.1 cgd return;
230 1.1 cgd ++found;
231 1.7 lukem if (isdigit(*s_load) && atoi(s_load) < load())
232 1.7 lukem errx(0, "Sorry, the load average is too high right now.");
233 1.7 lukem if (isdigit(*s_users) && atoi(s_users) <= users())
234 1.7 lukem errx(0, "Sorry, there are too many users logged on right now.");
235 1.1 cgd if (isdigit(*s_priority))
236 1.1 cgd priority = atoi(s_priority);
237 1.1 cgd }
238 1.1 cgd
239 1.1 cgd /*
240 1.1 cgd * load --
241 1.1 cgd * return 15 minute load average
242 1.1 cgd */
243 1.1 cgd double
244 1.1 cgd load()
245 1.1 cgd {
246 1.1 cgd double avenrun[3];
247 1.1 cgd
248 1.7 lukem if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
249 1.7 lukem err(1, "getloadavg() failed.");
250 1.9 mrg return (avenrun[2]);
251 1.1 cgd }
252 1.1 cgd
253 1.1 cgd /*
254 1.1 cgd * users --
255 1.1 cgd * return current number of users
256 1.1 cgd * todo: check idle time; if idle more than X minutes, don't
257 1.1 cgd * count them.
258 1.1 cgd */
259 1.7 lukem int
260 1.1 cgd users()
261 1.1 cgd {
262 1.1 cgd
263 1.7 lukem int nusers, utmp;
264 1.1 cgd struct utmp buf;
265 1.1 cgd
266 1.7 lukem if ((utmp = open(_PATH_UTMP, O_RDONLY, 0)) < 0)
267 1.7 lukem err(1, "%s", _PATH_UTMP);
268 1.1 cgd for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
269 1.1 cgd if (buf.ut_name[0] != '\0')
270 1.1 cgd ++nusers;
271 1.9 mrg return (nusers);
272 1.1 cgd }
273 1.1 cgd
274 1.7 lukem void
275 1.1 cgd nogamefile()
276 1.1 cgd {
277 1.7 lukem int fd, n;
278 1.1 cgd char buf[BUFSIZ];
279 1.1 cgd
280 1.1 cgd if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
281 1.1 cgd #define MESG "Sorry, no games right now.\n\n"
282 1.1 cgd (void)write(2, MESG, sizeof(MESG) - 1);
283 1.1 cgd while ((n = read(fd, buf, sizeof(buf))) > 0)
284 1.1 cgd (void)write(2, buf, n);
285 1.1 cgd exit(1);
286 1.1 cgd }
287 1.1 cgd }
288 1.1 cgd
289 1.1 cgd /*
290 1.1 cgd * hour --
291 1.1 cgd * print out the hour in human form
292 1.1 cgd */
293 1.7 lukem const char *
294 1.1 cgd hour(h)
295 1.1 cgd int h;
296 1.1 cgd {
297 1.12 hubertf static const char *const hours[] = {
298 1.7 lukem "midnight", "1am", "2am", "3am", "4am", "5am",
299 1.7 lukem "6am", "7am", "8am", "9am", "10am", "11am",
300 1.7 lukem "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
301 1.13 jsm "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
302 1.7 lukem
303 1.13 jsm if (h < 0 || h > 24)
304 1.9 mrg return ("BAD TIME");
305 1.7 lukem else
306 1.9 mrg return (hours[h]);
307 1.1 cgd }
308 1.1 cgd
309 1.1 cgd #ifdef LOG
310 1.1 cgd /*
311 1.1 cgd * logfile --
312 1.1 cgd * log play of game
313 1.1 cgd */
314 1.1 cgd logfile()
315 1.1 cgd {
316 1.4 cgd struct passwd *pw;
317 1.1 cgd FILE *lp;
318 1.1 cgd uid_t uid;
319 1.1 cgd int lock_cnt;
320 1.1 cgd
321 1.1 cgd if (lp = fopen(_PATH_LOG, "a")) {
322 1.1 cgd for (lock_cnt = 0;; ++lock_cnt) {
323 1.1 cgd if (!flock(fileno(lp), LOCK_EX))
324 1.1 cgd break;
325 1.1 cgd if (lock_cnt == 4) {
326 1.7 lukem warnx("log lock");
327 1.1 cgd (void)fclose(lp);
328 1.1 cgd return;
329 1.1 cgd }
330 1.1 cgd sleep((u_int)1);
331 1.1 cgd }
332 1.1 cgd if (pw = getpwuid(uid = getuid()))
333 1.1 cgd fputs(pw->pw_name, lp);
334 1.1 cgd else
335 1.1 cgd fprintf(lp, "%u", uid);
336 1.1 cgd fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
337 1.1 cgd (void)fclose(lp);
338 1.1 cgd (void)flock(fileno(lp), LOCK_UN);
339 1.1 cgd }
340 1.1 cgd }
341 1.1 cgd #endif /* LOG */
342