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