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