dm.c revision 1.28 1 1.28 dholland /* $NetBSD: dm.c,v 1.28 2009/08/12 05:51:59 dholland 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.26 lukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
35 1.26 lukem The Regents of the University of California. All rights reserved.");
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.28 dholland __RCSID("$NetBSD: dm.c,v 1.28 2009/08/12 05:51:59 dholland 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.28 dholland static void c_day(const char *, const char *, const char *);
70 1.28 dholland static void c_game(const char *, const char *, const char *, const char *);
71 1.28 dholland static void c_tty(const char *);
72 1.28 dholland static const char *hour(int);
73 1.28 dholland static double load(void);
74 1.28 dholland static void nogamefile(void);
75 1.28 dholland static void play(char **) __dead;
76 1.28 dholland static void read_config(void);
77 1.28 dholland static int users(void);
78 1.28 dholland
79 1.28 dholland #ifdef LOG
80 1.28 dholland static void logfile(void);
81 1.28 dholland #endif
82 1.7 lukem
83 1.4 cgd int
84 1.24 perry main(int argc __unused, char *argv[])
85 1.1 cgd {
86 1.4 cgd char *cp;
87 1.1 cgd
88 1.1 cgd nogamefile();
89 1.7 lukem game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
90 1.1 cgd
91 1.1 cgd if (!strcmp(game, "dm"))
92 1.1 cgd exit(0);
93 1.1 cgd
94 1.1 cgd gametty = ttyname(0);
95 1.10 hubertf unsetenv("TZ");
96 1.1 cgd (void)time(&now);
97 1.1 cgd read_config();
98 1.1 cgd #ifdef LOG
99 1.1 cgd logfile();
100 1.1 cgd #endif
101 1.1 cgd play(argv);
102 1.1 cgd /*NOTREACHED*/
103 1.9 mrg return (0);
104 1.1 cgd }
105 1.1 cgd
106 1.1 cgd /*
107 1.1 cgd * play --
108 1.1 cgd * play the game
109 1.1 cgd */
110 1.28 dholland static void
111 1.22 jmc play(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.28 dholland static void
127 1.22 jmc read_config(void)
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.23 dan if (sscanf(lbuf, "%39s%39s", 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.23 dan if (sscanf(lbuf, "%39s%39s%39s%39s%39s",
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.23 dan if (sscanf(lbuf, "%39s%39s%39s%39s", 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.28 dholland static void
162 1.22 jmc c_day(const char *s_day, const char *s_start, const char *s_stop)
163 1.1 cgd {
164 1.12 hubertf static const char *const days[] = {
165 1.1 cgd "sunday", "monday", "tuesday", "wednesday",
166 1.1 cgd "thursday", "friday", "saturday",
167 1.1 cgd };
168 1.1 cgd static struct tm *ct;
169 1.1 cgd int start, stop;
170 1.1 cgd
171 1.1 cgd if (!ct)
172 1.1 cgd ct = localtime(&now);
173 1.1 cgd if (strcasecmp(s_day, days[ct->tm_wday]))
174 1.1 cgd return;
175 1.22 jmc if (!isdigit((unsigned char)*s_start) ||
176 1.22 jmc !isdigit((unsigned char)*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.28 dholland static void
194 1.22 jmc c_tty(const char *tty)
195 1.1 cgd {
196 1.1 cgd static int first = 1;
197 1.1 cgd static char *p_tty;
198 1.1 cgd
199 1.1 cgd if (first) {
200 1.7 lukem p_tty = strrchr(gametty, '/');
201 1.1 cgd first = 0;
202 1.1 cgd }
203 1.1 cgd
204 1.7 lukem if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
205 1.7 lukem errx(1, "Sorry, you may not play games on %s.", gametty);
206 1.1 cgd }
207 1.1 cgd
208 1.1 cgd /*
209 1.1 cgd * c_game --
210 1.1 cgd * see if game can be played now.
211 1.1 cgd */
212 1.28 dholland static void
213 1.22 jmc c_game(const char *s_game, const char *s_load, const char *s_users,
214 1.22 jmc const char *s_priority)
215 1.1 cgd {
216 1.1 cgd static int found;
217 1.1 cgd
218 1.1 cgd if (found)
219 1.1 cgd return;
220 1.1 cgd if (strcmp(game, s_game) && strcasecmp("default", s_game))
221 1.1 cgd return;
222 1.1 cgd ++found;
223 1.21 dsl if (isdigit((unsigned char)*s_load) && atoi(s_load) < load())
224 1.7 lukem errx(0, "Sorry, the load average is too high right now.");
225 1.21 dsl if (isdigit((unsigned char)*s_users) && atoi(s_users) <= users())
226 1.7 lukem errx(0, "Sorry, there are too many users logged on right now.");
227 1.21 dsl if (isdigit((unsigned char)*s_priority))
228 1.1 cgd priority = atoi(s_priority);
229 1.1 cgd }
230 1.1 cgd
231 1.1 cgd /*
232 1.1 cgd * load --
233 1.1 cgd * return 15 minute load average
234 1.1 cgd */
235 1.28 dholland static double
236 1.22 jmc load(void)
237 1.1 cgd {
238 1.1 cgd double avenrun[3];
239 1.1 cgd
240 1.7 lukem if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
241 1.15 jsm err(1, "getloadavg() failed");
242 1.9 mrg return (avenrun[2]);
243 1.1 cgd }
244 1.1 cgd
245 1.1 cgd /*
246 1.1 cgd * users --
247 1.1 cgd * return current number of users
248 1.1 cgd * todo: check idle time; if idle more than X minutes, don't
249 1.1 cgd * count them.
250 1.1 cgd */
251 1.28 dholland static int
252 1.22 jmc users(void)
253 1.1 cgd {
254 1.17 christos struct utmpentry *ep;
255 1.17 christos int nusers;
256 1.17 christos
257 1.17 christos nusers = getutentries(NULL, &ep);
258 1.17 christos return nusers;
259 1.1 cgd }
260 1.1 cgd
261 1.28 dholland static void
262 1.22 jmc nogamefile(void)
263 1.1 cgd {
264 1.7 lukem int fd, n;
265 1.1 cgd char buf[BUFSIZ];
266 1.1 cgd
267 1.1 cgd if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
268 1.1 cgd #define MESG "Sorry, no games right now.\n\n"
269 1.1 cgd (void)write(2, MESG, sizeof(MESG) - 1);
270 1.1 cgd while ((n = read(fd, buf, sizeof(buf))) > 0)
271 1.1 cgd (void)write(2, buf, n);
272 1.1 cgd exit(1);
273 1.1 cgd }
274 1.1 cgd }
275 1.1 cgd
276 1.1 cgd /*
277 1.1 cgd * hour --
278 1.1 cgd * print out the hour in human form
279 1.1 cgd */
280 1.28 dholland static const char *
281 1.22 jmc hour(int h)
282 1.1 cgd {
283 1.12 hubertf static const char *const hours[] = {
284 1.7 lukem "midnight", "1am", "2am", "3am", "4am", "5am",
285 1.7 lukem "6am", "7am", "8am", "9am", "10am", "11am",
286 1.7 lukem "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
287 1.13 jsm "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
288 1.7 lukem
289 1.13 jsm if (h < 0 || h > 24)
290 1.9 mrg return ("BAD TIME");
291 1.7 lukem else
292 1.9 mrg return (hours[h]);
293 1.1 cgd }
294 1.1 cgd
295 1.1 cgd #ifdef LOG
296 1.1 cgd /*
297 1.1 cgd * logfile --
298 1.1 cgd * log play of game
299 1.1 cgd */
300 1.28 dholland static void
301 1.22 jmc logfile(void)
302 1.1 cgd {
303 1.4 cgd struct passwd *pw;
304 1.1 cgd FILE *lp;
305 1.1 cgd uid_t uid;
306 1.1 cgd int lock_cnt;
307 1.1 cgd
308 1.1 cgd if (lp = fopen(_PATH_LOG, "a")) {
309 1.1 cgd for (lock_cnt = 0;; ++lock_cnt) {
310 1.1 cgd if (!flock(fileno(lp), LOCK_EX))
311 1.1 cgd break;
312 1.1 cgd if (lock_cnt == 4) {
313 1.7 lukem warnx("log lock");
314 1.1 cgd (void)fclose(lp);
315 1.1 cgd return;
316 1.1 cgd }
317 1.1 cgd sleep((u_int)1);
318 1.1 cgd }
319 1.1 cgd if (pw = getpwuid(uid = getuid()))
320 1.1 cgd fputs(pw->pw_name, lp);
321 1.1 cgd else
322 1.1 cgd fprintf(lp, "%u", uid);
323 1.1 cgd fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
324 1.27 dholland (void)flock(fileno(lp), LOCK_UN);
325 1.1 cgd (void)fclose(lp);
326 1.1 cgd }
327 1.1 cgd }
328 1.1 cgd #endif /* LOG */
329