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