dm.c revision 1.24 1 1.24 perry /* $NetBSD: dm.c,v 1.24 2007/12/15 19:44:40 perry 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.24 perry __RCSID("$NetBSD: dm.c,v 1.24 2007/12/15 19:44:40 perry 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 void nogamefile(void);
75 1.24 perry void play(char **) __dead;
76 1.19 jsm void read_config(void);
77 1.19 jsm int users(void);
78 1.7 lukem
79 1.4 cgd int
80 1.24 perry main(int argc __unused, char *argv[])
81 1.1 cgd {
82 1.4 cgd char *cp;
83 1.1 cgd
84 1.1 cgd nogamefile();
85 1.7 lukem game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
86 1.1 cgd
87 1.1 cgd if (!strcmp(game, "dm"))
88 1.1 cgd exit(0);
89 1.1 cgd
90 1.1 cgd gametty = ttyname(0);
91 1.10 hubertf unsetenv("TZ");
92 1.1 cgd (void)time(&now);
93 1.1 cgd read_config();
94 1.1 cgd #ifdef LOG
95 1.1 cgd logfile();
96 1.1 cgd #endif
97 1.1 cgd play(argv);
98 1.1 cgd /*NOTREACHED*/
99 1.9 mrg return (0);
100 1.1 cgd }
101 1.1 cgd
102 1.1 cgd /*
103 1.1 cgd * play --
104 1.1 cgd * play the game
105 1.1 cgd */
106 1.7 lukem void
107 1.22 jmc play(char **args)
108 1.1 cgd {
109 1.2 mycroft char pbuf[MAXPATHLEN];
110 1.1 cgd
111 1.16 jdolecek snprintf(pbuf, sizeof(pbuf), "%s%s", _PATH_HIDE, game);
112 1.1 cgd if (priority > 0) /* < 0 requires root */
113 1.1 cgd (void)setpriority(PRIO_PROCESS, 0, priority);
114 1.1 cgd execv(pbuf, args);
115 1.7 lukem err(1, "%s", pbuf);
116 1.1 cgd }
117 1.1 cgd
118 1.1 cgd /*
119 1.1 cgd * read_config --
120 1.1 cgd * read through config file, looking for key words.
121 1.1 cgd */
122 1.7 lukem void
123 1.22 jmc read_config(void)
124 1.1 cgd {
125 1.1 cgd FILE *cfp;
126 1.1 cgd char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
127 1.1 cgd
128 1.1 cgd if (!(cfp = fopen(_PATH_CONFIG, "r")))
129 1.1 cgd return;
130 1.1 cgd while (fgets(lbuf, sizeof(lbuf), cfp))
131 1.9 mrg switch (*lbuf) {
132 1.1 cgd case 'b': /* badtty */
133 1.23 dan if (sscanf(lbuf, "%39s%39s", f1, f2) != 2 ||
134 1.1 cgd strcasecmp(f1, "badtty"))
135 1.1 cgd break;
136 1.1 cgd c_tty(f2);
137 1.1 cgd break;
138 1.1 cgd case 'g': /* game */
139 1.23 dan if (sscanf(lbuf, "%39s%39s%39s%39s%39s",
140 1.1 cgd f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
141 1.1 cgd break;
142 1.1 cgd c_game(f2, f3, f4, f5);
143 1.1 cgd break;
144 1.1 cgd case 't': /* time */
145 1.23 dan if (sscanf(lbuf, "%39s%39s%39s%39s", f1, f2, f3, f4) != 4 ||
146 1.1 cgd strcasecmp(f1, "time"))
147 1.1 cgd break;
148 1.1 cgd c_day(f2, f3, f4);
149 1.1 cgd }
150 1.1 cgd (void)fclose(cfp);
151 1.1 cgd }
152 1.1 cgd
153 1.1 cgd /*
154 1.1 cgd * c_day --
155 1.1 cgd * if day is today, see if okay to play
156 1.1 cgd */
157 1.7 lukem void
158 1.22 jmc c_day(const char *s_day, const char *s_start, const char *s_stop)
159 1.1 cgd {
160 1.12 hubertf static const char *const days[] = {
161 1.1 cgd "sunday", "monday", "tuesday", "wednesday",
162 1.1 cgd "thursday", "friday", "saturday",
163 1.1 cgd };
164 1.1 cgd static struct tm *ct;
165 1.1 cgd int start, stop;
166 1.1 cgd
167 1.1 cgd if (!ct)
168 1.1 cgd ct = localtime(&now);
169 1.1 cgd if (strcasecmp(s_day, days[ct->tm_wday]))
170 1.1 cgd return;
171 1.22 jmc if (!isdigit((unsigned char)*s_start) ||
172 1.22 jmc !isdigit((unsigned char)*s_stop))
173 1.1 cgd return;
174 1.1 cgd start = atoi(s_start);
175 1.1 cgd stop = atoi(s_stop);
176 1.13 jsm if (ct->tm_hour >= start && ct->tm_hour < stop) {
177 1.13 jsm if (start == 0 && stop == 24)
178 1.13 jsm errx(0, "Sorry, games are not available today.");
179 1.13 jsm else
180 1.13 jsm errx(0, "Sorry, games are not available from %s to %s today.",
181 1.13 jsm hour(start), hour(stop));
182 1.13 jsm }
183 1.1 cgd }
184 1.1 cgd
185 1.1 cgd /*
186 1.1 cgd * c_tty --
187 1.1 cgd * decide if this tty can be used for games.
188 1.1 cgd */
189 1.7 lukem void
190 1.22 jmc c_tty(const char *tty)
191 1.1 cgd {
192 1.1 cgd static int first = 1;
193 1.1 cgd static char *p_tty;
194 1.1 cgd
195 1.1 cgd if (first) {
196 1.7 lukem p_tty = strrchr(gametty, '/');
197 1.1 cgd first = 0;
198 1.1 cgd }
199 1.1 cgd
200 1.7 lukem if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
201 1.7 lukem errx(1, "Sorry, you may not play games on %s.", gametty);
202 1.1 cgd }
203 1.1 cgd
204 1.1 cgd /*
205 1.1 cgd * c_game --
206 1.1 cgd * see if game can be played now.
207 1.1 cgd */
208 1.7 lukem void
209 1.22 jmc c_game(const char *s_game, const char *s_load, const char *s_users,
210 1.22 jmc const char *s_priority)
211 1.1 cgd {
212 1.1 cgd static int found;
213 1.1 cgd
214 1.1 cgd if (found)
215 1.1 cgd return;
216 1.1 cgd if (strcmp(game, s_game) && strcasecmp("default", s_game))
217 1.1 cgd return;
218 1.1 cgd ++found;
219 1.21 dsl if (isdigit((unsigned char)*s_load) && atoi(s_load) < load())
220 1.7 lukem errx(0, "Sorry, the load average is too high right now.");
221 1.21 dsl if (isdigit((unsigned char)*s_users) && atoi(s_users) <= users())
222 1.7 lukem errx(0, "Sorry, there are too many users logged on right now.");
223 1.21 dsl if (isdigit((unsigned char)*s_priority))
224 1.1 cgd priority = atoi(s_priority);
225 1.1 cgd }
226 1.1 cgd
227 1.1 cgd /*
228 1.1 cgd * load --
229 1.1 cgd * return 15 minute load average
230 1.1 cgd */
231 1.1 cgd double
232 1.22 jmc load(void)
233 1.1 cgd {
234 1.1 cgd double avenrun[3];
235 1.1 cgd
236 1.7 lukem if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
237 1.15 jsm err(1, "getloadavg() failed");
238 1.9 mrg return (avenrun[2]);
239 1.1 cgd }
240 1.1 cgd
241 1.1 cgd /*
242 1.1 cgd * users --
243 1.1 cgd * return current number of users
244 1.1 cgd * todo: check idle time; if idle more than X minutes, don't
245 1.1 cgd * count them.
246 1.1 cgd */
247 1.7 lukem int
248 1.22 jmc users(void)
249 1.1 cgd {
250 1.17 christos static struct utmpentry *ohead = NULL;
251 1.17 christos struct utmpentry *ep;
252 1.17 christos int nusers;
253 1.17 christos
254 1.17 christos nusers = getutentries(NULL, &ep);
255 1.17 christos if (ep != ohead) {
256 1.17 christos freeutentries(ep);
257 1.17 christos ohead = ep;
258 1.17 christos }
259 1.17 christos return nusers;
260 1.1 cgd }
261 1.1 cgd
262 1.7 lukem void
263 1.22 jmc nogamefile(void)
264 1.1 cgd {
265 1.7 lukem int fd, n;
266 1.1 cgd char buf[BUFSIZ];
267 1.1 cgd
268 1.1 cgd if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
269 1.1 cgd #define MESG "Sorry, no games right now.\n\n"
270 1.1 cgd (void)write(2, MESG, sizeof(MESG) - 1);
271 1.1 cgd while ((n = read(fd, buf, sizeof(buf))) > 0)
272 1.1 cgd (void)write(2, buf, n);
273 1.1 cgd exit(1);
274 1.1 cgd }
275 1.1 cgd }
276 1.1 cgd
277 1.1 cgd /*
278 1.1 cgd * hour --
279 1.1 cgd * print out the hour in human form
280 1.1 cgd */
281 1.7 lukem const char *
282 1.22 jmc hour(int h)
283 1.1 cgd {
284 1.12 hubertf static const char *const hours[] = {
285 1.7 lukem "midnight", "1am", "2am", "3am", "4am", "5am",
286 1.7 lukem "6am", "7am", "8am", "9am", "10am", "11am",
287 1.7 lukem "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
288 1.13 jsm "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
289 1.7 lukem
290 1.13 jsm if (h < 0 || h > 24)
291 1.9 mrg return ("BAD TIME");
292 1.7 lukem else
293 1.9 mrg return (hours[h]);
294 1.1 cgd }
295 1.1 cgd
296 1.1 cgd #ifdef LOG
297 1.1 cgd /*
298 1.1 cgd * logfile --
299 1.1 cgd * log play of game
300 1.1 cgd */
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.1 cgd (void)fclose(lp);
325 1.1 cgd (void)flock(fileno(lp), LOCK_UN);
326 1.1 cgd }
327 1.1 cgd }
328 1.1 cgd #endif /* LOG */
329