dm.c revision 1.9 1 1.9 mrg /* $NetBSD: dm.c,v 1.9 1998/07/04 20:06:55 mrg 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.9 mrg __RCSID("$NetBSD: dm.c,v 1.9 1998/07/04 20:06:55 mrg 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.4 cgd #include <nlist.h>
59 1.1 cgd #include <pwd.h>
60 1.1 cgd #include <stdio.h>
61 1.7 lukem #include <stdlib.h>
62 1.2 mycroft #include <string.h>
63 1.4 cgd #include <time.h>
64 1.4 cgd #include <unistd.h>
65 1.4 cgd #include <utmp.h>
66 1.4 cgd
67 1.1 cgd #include "pathnames.h"
68 1.1 cgd
69 1.1 cgd static time_t now; /* current time value */
70 1.1 cgd static int priority = 0; /* priority game runs at */
71 1.1 cgd static char *game, /* requested game */
72 1.1 cgd *gametty; /* from tty? */
73 1.1 cgd
74 1.7 lukem void c_day __P((char *, char *, char *));
75 1.7 lukem void c_game __P((char *, char *, char *, char *));
76 1.7 lukem void c_tty __P((char *));
77 1.7 lukem const char *hour __P((int));
78 1.7 lukem double load __P((void));
79 1.7 lukem int main __P((int, char *[]));
80 1.7 lukem void nogamefile __P((void));
81 1.7 lukem void play __P((char **));
82 1.7 lukem void read_config __P((void));
83 1.7 lukem int users __P((void));
84 1.7 lukem
85 1.4 cgd int
86 1.1 cgd main(argc, argv)
87 1.1 cgd int argc;
88 1.4 cgd char *argv[];
89 1.1 cgd {
90 1.4 cgd char *cp;
91 1.1 cgd
92 1.1 cgd nogamefile();
93 1.7 lukem game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
94 1.1 cgd
95 1.1 cgd if (!strcmp(game, "dm"))
96 1.1 cgd exit(0);
97 1.1 cgd
98 1.1 cgd gametty = ttyname(0);
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.1 cgd char *s_day, *s_start, *s_stop;
171 1.1 cgd {
172 1.1 cgd static char *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.7 lukem if (ct->tm_hour >= start && ct->tm_hour < stop)
188 1.7 lukem errx(0, "Sorry, games are not available from %s to %s today.",
189 1.7 lukem hour(start), hour(stop));
190 1.1 cgd }
191 1.1 cgd
192 1.1 cgd /*
193 1.1 cgd * c_tty --
194 1.1 cgd * decide if this tty can be used for games.
195 1.1 cgd */
196 1.7 lukem void
197 1.1 cgd c_tty(tty)
198 1.1 cgd char *tty;
199 1.1 cgd {
200 1.1 cgd static int first = 1;
201 1.1 cgd static char *p_tty;
202 1.1 cgd
203 1.1 cgd if (first) {
204 1.7 lukem p_tty = strrchr(gametty, '/');
205 1.1 cgd first = 0;
206 1.1 cgd }
207 1.1 cgd
208 1.7 lukem if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
209 1.7 lukem errx(1, "Sorry, you may not play games on %s.", gametty);
210 1.1 cgd }
211 1.1 cgd
212 1.1 cgd /*
213 1.1 cgd * c_game --
214 1.1 cgd * see if game can be played now.
215 1.1 cgd */
216 1.7 lukem void
217 1.1 cgd c_game(s_game, s_load, s_users, s_priority)
218 1.1 cgd char *s_game, *s_load, *s_users, *s_priority;
219 1.1 cgd {
220 1.1 cgd static int found;
221 1.1 cgd
222 1.1 cgd if (found)
223 1.1 cgd return;
224 1.1 cgd if (strcmp(game, s_game) && strcasecmp("default", s_game))
225 1.1 cgd return;
226 1.1 cgd ++found;
227 1.7 lukem if (isdigit(*s_load) && atoi(s_load) < load())
228 1.7 lukem errx(0, "Sorry, the load average is too high right now.");
229 1.7 lukem if (isdigit(*s_users) && atoi(s_users) <= users())
230 1.7 lukem errx(0, "Sorry, there are too many users logged on right now.");
231 1.1 cgd if (isdigit(*s_priority))
232 1.1 cgd priority = atoi(s_priority);
233 1.1 cgd }
234 1.1 cgd
235 1.1 cgd /*
236 1.1 cgd * load --
237 1.1 cgd * return 15 minute load average
238 1.1 cgd */
239 1.1 cgd double
240 1.1 cgd load()
241 1.1 cgd {
242 1.1 cgd double avenrun[3];
243 1.1 cgd
244 1.7 lukem if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
245 1.7 lukem err(1, "getloadavg() failed.");
246 1.9 mrg return (avenrun[2]);
247 1.1 cgd }
248 1.1 cgd
249 1.1 cgd /*
250 1.1 cgd * users --
251 1.1 cgd * return current number of users
252 1.1 cgd * todo: check idle time; if idle more than X minutes, don't
253 1.1 cgd * count them.
254 1.1 cgd */
255 1.7 lukem int
256 1.1 cgd users()
257 1.1 cgd {
258 1.1 cgd
259 1.7 lukem int nusers, utmp;
260 1.1 cgd struct utmp buf;
261 1.1 cgd
262 1.7 lukem if ((utmp = open(_PATH_UTMP, O_RDONLY, 0)) < 0)
263 1.7 lukem err(1, "%s", _PATH_UTMP);
264 1.1 cgd for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;)
265 1.1 cgd if (buf.ut_name[0] != '\0')
266 1.1 cgd ++nusers;
267 1.9 mrg return (nusers);
268 1.1 cgd }
269 1.1 cgd
270 1.7 lukem void
271 1.1 cgd nogamefile()
272 1.1 cgd {
273 1.7 lukem int fd, n;
274 1.1 cgd char buf[BUFSIZ];
275 1.1 cgd
276 1.1 cgd if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
277 1.1 cgd #define MESG "Sorry, no games right now.\n\n"
278 1.1 cgd (void)write(2, MESG, sizeof(MESG) - 1);
279 1.1 cgd while ((n = read(fd, buf, sizeof(buf))) > 0)
280 1.1 cgd (void)write(2, buf, n);
281 1.1 cgd exit(1);
282 1.1 cgd }
283 1.1 cgd }
284 1.1 cgd
285 1.1 cgd /*
286 1.1 cgd * hour --
287 1.1 cgd * print out the hour in human form
288 1.1 cgd */
289 1.7 lukem const char *
290 1.1 cgd hour(h)
291 1.1 cgd int h;
292 1.1 cgd {
293 1.7 lukem static char *hours[] = {
294 1.7 lukem "midnight", "1am", "2am", "3am", "4am", "5am",
295 1.7 lukem "6am", "7am", "8am", "9am", "10am", "11am",
296 1.7 lukem "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
297 1.7 lukem "6pm", "7pm", "8pm", "9pm", "10pm", "11pm" };
298 1.7 lukem
299 1.7 lukem if (h < 0 || h > 23)
300 1.9 mrg return ("BAD TIME");
301 1.7 lukem else
302 1.9 mrg return (hours[h]);
303 1.1 cgd }
304 1.1 cgd
305 1.1 cgd #ifdef LOG
306 1.1 cgd /*
307 1.1 cgd * logfile --
308 1.1 cgd * log play of game
309 1.1 cgd */
310 1.1 cgd logfile()
311 1.1 cgd {
312 1.4 cgd struct passwd *pw;
313 1.1 cgd FILE *lp;
314 1.1 cgd uid_t uid;
315 1.1 cgd int lock_cnt;
316 1.1 cgd
317 1.1 cgd if (lp = fopen(_PATH_LOG, "a")) {
318 1.1 cgd for (lock_cnt = 0;; ++lock_cnt) {
319 1.1 cgd if (!flock(fileno(lp), LOCK_EX))
320 1.1 cgd break;
321 1.1 cgd if (lock_cnt == 4) {
322 1.7 lukem warnx("log lock");
323 1.1 cgd (void)fclose(lp);
324 1.1 cgd return;
325 1.1 cgd }
326 1.1 cgd sleep((u_int)1);
327 1.1 cgd }
328 1.1 cgd if (pw = getpwuid(uid = getuid()))
329 1.1 cgd fputs(pw->pw_name, lp);
330 1.1 cgd else
331 1.1 cgd fprintf(lp, "%u", uid);
332 1.1 cgd fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
333 1.1 cgd (void)fclose(lp);
334 1.1 cgd (void)flock(fileno(lp), LOCK_UN);
335 1.1 cgd }
336 1.1 cgd }
337 1.1 cgd #endif /* LOG */
338