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