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.9 (Berkeley) 09/26/88"; 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 38 static time_t now; /* current time value */ 39 static int priority = 0; /* priority game runs at */ 40 static char *game, /* requested game */ 41 *gametty; /* from tty? */ 42 43 /*ARGSUSED*/ 44 main(argc, argv) 45 int argc; 46 char **argv; 47 { 48 char *cp, *rindex(), *ttyname(); 49 time_t time(); 50 51 nogamefile(); 52 game = (cp = rindex(*argv, '/')) ? ++cp : *argv; 53 54 if (!strcmp(game, "dm")) 55 exit(0); 56 57 gametty = ttyname(0); 58 (void)time(&now); 59 read_config(); 60 #ifdef LOG 61 logfile(); 62 #endif 63 play(argv); 64 /*NOTREACHED*/ 65 } 66 67 /* 68 * play -- 69 * play the game 70 */ 71 #define GAMEHIDE "/usr/games/hide/" 72 static 73 play(args) 74 char **args; 75 { 76 char pbuf[MAXPATHLEN], *strcpy(); 77 78 (void)strcpy(pbuf, GAMEHIDE); 79 (void)strcpy(pbuf + sizeof(GAMEHIDE) - 1, game); 80 if (priority > 0) /* < 0 requires root */ 81 (void)setpriority(PRIO_PROCESS, 0, priority); 82 setgid(getgid()); /* we run setgid kmem; lose it */ 83 execv(pbuf, args); 84 perror("dm"); 85 exit(1); 86 } 87 88 /* 89 * read_config -- 90 * read through config file, looking for key words. 91 */ 92 #define CONTROL "/usr/games/dm.config" 93 static 94 read_config() 95 { 96 FILE *cfp; 97 char *control, *host, *index(), *strcpy(); 98 char lbuf[BUFSIZ], path[MAXHOSTNAMELEN + sizeof(CONTROL)]; 99 char f1[40], f2[40], f3[40], f4[40], f5[40]; 100 101 host = &path[sizeof(CONTROL)]; 102 if (gethostname(host, MAXHOSTNAMELEN)) { 103 perror("dm: gethostname"); 104 exit(1); 105 } 106 (void)strcpy(path, control = CONTROL); 107 host[-1] = '.'; 108 if (host = index(host, '.')) 109 *host = '\0'; 110 if (!(cfp = fopen(path, "r")) && !(cfp = fopen(control, "r"))) { 111 fprintf(stderr, "dm: unable to read %s or %s.\n", 112 path, control); 113 exit(1); 114 } 115 while (fgets(lbuf, sizeof(lbuf), cfp)) 116 switch(*lbuf) { 117 case 'b': /* badtty */ 118 if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 119 strcasecmp(f1, "badtty")) 120 break; 121 c_tty(f2); 122 break; 123 case 'g': /* game */ 124 if (sscanf(lbuf, "%s%s%s%s%s", 125 f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 126 break; 127 c_game(f2, f3, f4, f5); 128 break; 129 case 't': /* time */ 130 if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 131 strcasecmp(f1, "time")) 132 break; 133 c_day(f2, f3, f4); 134 } 135 (void)fclose(cfp); 136 } 137 138 /* 139 * c_day -- 140 * if day is today, see if okay to play 141 */ 142 static 143 c_day(s_day, s_start, s_stop) 144 char *s_day, *s_start, *s_stop; 145 { 146 static char *days[] = { 147 "sunday", "monday", "tuesday", "wednesday", 148 "thursday", "friday", "saturday", 149 }; 150 static struct tm *ct; 151 int start, stop; 152 153 if (!ct) 154 ct = localtime(&now); 155 if (strcasecmp(s_day, days[ct->tm_wday])) 156 return; 157 if (!isdigit(*s_start) || !isdigit(*s_stop)) 158 return; 159 start = atoi(s_start); 160 stop = atoi(s_stop); 161 if (ct->tm_hour >= start && ct->tm_hour < stop) { 162 fputs("dm: Sorry, games are not available from ", stderr); 163 hour(start); 164 fputs(" to ", stderr); 165 hour(stop); 166 fputs(" today.\n", stderr); 167 exit(0); 168 } 169 } 170 171 /* 172 * c_tty -- 173 * decide if this tty can be used for games. 174 */ 175 static 176 c_tty(tty) 177 char *tty; 178 { 179 static int first = 1; 180 static char *p_tty; 181 char *rindex(); 182 183 if (first) { 184 p_tty = rindex(gametty, '/'); 185 first = 0; 186 } 187 188 if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 189 fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 190 exit(0); 191 } 192 } 193 194 /* 195 * c_game -- 196 * see if game can be played now. 197 */ 198 static 199 c_game(s_game, s_load, s_users, s_priority) 200 char *s_game, *s_load, *s_users, *s_priority; 201 { 202 static int found; 203 double load(); 204 205 if (found) 206 return; 207 if (strcmp(game, s_game) && strcasecmp("default", s_game)) 208 return; 209 ++found; 210 if (isdigit(*s_load) && atoi(s_load) < load()) { 211 fputs("dm: Sorry, the load average is too high right now.\n", stderr); 212 exit(0); 213 } 214 if (isdigit(*s_users) && atoi(s_users) <= users()) { 215 fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 216 exit(0); 217 } 218 if (isdigit(*s_priority)) 219 priority = atoi(s_priority); 220 } 221 222 static struct nlist nl[] = { 223 { "_avenrun" }, 224 #define X_AVENRUN 0 225 { "" }, 226 }; 227 228 /* 229 * load -- 230 * return 15 minute load average 231 */ 232 static double 233 load() 234 { 235 double avenrun[3]; 236 int kmem; 237 long lseek(); 238 239 if (nlist("/vmunix", nl)) { 240 fputs("dm: nlist of /vmunix failed.\n", stderr); 241 exit(1); 242 } 243 if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 244 perror("dm: /dev/kmem"); 245 exit(1); 246 } 247 (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 248 (void)read(kmem, (char *)avenrun, sizeof(avenrun)); 249 return(avenrun[2]); 250 } 251 252 /* 253 * users -- 254 * return current number of users 255 * todo: check idle time; if idle more than X minutes, don't 256 * count them. 257 */ 258 static 259 users() 260 { 261 register int nusers, utmp; 262 struct utmp buf; 263 264 if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 265 perror("dm: /etc/utmp"); 266 exit(1); 267 } 268 for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 269 if (buf.ut_name[0] != '\0') 270 ++nusers; 271 return(nusers); 272 } 273 274 /* 275 * nogamefile -- 276 * if the file NOGAMING exists, no games allowed. 277 * file may also contain a message for the user. 278 */ 279 #define NOGAMING "/usr/games/nogames" 280 static 281 nogamefile() 282 { 283 register int fd, n; 284 char buf[BUFSIZ]; 285 286 if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 287 #define MESG "Sorry, no games right now.\n\n" 288 (void)write(2, MESG, sizeof(MESG) - 1); 289 while ((n = read(fd, buf, sizeof(buf))) > 0) 290 (void)write(2, buf, n); 291 exit(1); 292 } 293 } 294 295 /* 296 * hour -- 297 * print out the hour in human form 298 */ 299 static 300 hour(h) 301 int h; 302 { 303 switch(h) { 304 case 0: 305 fputs("midnight", stderr); 306 break; 307 case 12: 308 fputs("noon", stderr); 309 break; 310 default: 311 if (h > 12) 312 fprintf(stderr, "%dpm", h - 12); 313 else 314 fprintf(stderr, "%dam", h); 315 } 316 } 317 318 #ifdef LOG 319 /* 320 * logfile -- 321 * log play of game 322 */ 323 #define LOGFILE "/usr/adm/dm.log" 324 static 325 logfile() 326 { 327 struct passwd *pw, *getpwuid(); 328 FILE *lp; 329 uid_t uid; 330 int lock_cnt; 331 char *ctime(); 332 333 if (lp = fopen(LOGFILE, "a")) { 334 for (lock_cnt = 0;; ++lock_cnt) { 335 if (!flock(fileno(lp), LOCK_EX)) 336 break; 337 if (lock_cnt == 4) { 338 perror("dm: log lock"); 339 (void)fclose(lp); 340 return; 341 } 342 sleep((u_int)1); 343 } 344 if (pw = getpwuid(uid = getuid())) 345 fputs(pw->pw_name, lp); 346 else 347 fprintf(lp, "%u", uid); 348 fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 349 (void)fclose(lp); 350 (void)flock(fileno(lp), LOCK_UN); 351 } 352 } 353 #endif /* LOG */ 354