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