1*32216Sbostic /* 2*32216Sbostic * Copyright (c) 1987 Regents of the University of California. 3*32216Sbostic * All rights reserved. The Berkeley software License Agreement 4*32216Sbostic * specifies the terms and conditions for redistribution. 5*32216Sbostic */ 6*32216Sbostic 7*32216Sbostic #ifndef lint 8*32216Sbostic char copyright[] = 9*32216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 10*32216Sbostic All rights reserved.\n"; 11*32216Sbostic #endif not lint 12*32216Sbostic 13*32216Sbostic #ifndef lint 14*32216Sbostic static char sccsid[] = "@(#)dm.c 5.1 (Berkeley) 09/18/87"; 15*32216Sbostic #endif not lint 16*32216Sbostic 17*32216Sbostic #include <sys/param.h> 18*32216Sbostic #include <sys/file.h> 19*32216Sbostic #include <sys/time.h> 20*32216Sbostic #include <sys/resource.h> 21*32216Sbostic #include <pwd.h> 22*32216Sbostic #include <utmp.h> 23*32216Sbostic #include <nlist.h> 24*32216Sbostic #include <stdio.h> 25*32216Sbostic #include <ctype.h> 26*32216Sbostic 27*32216Sbostic #define LOG /* if want game usage logged */ 28*32216Sbostic 29*32216Sbostic #define GAMEHIDE "/usr/games/hide" 30*32216Sbostic #define NOGAMING "/etc/nogames" 31*32216Sbostic #define CONTROL "/usr/games/game.control" 32*32216Sbostic #ifdef LOG 33*32216Sbostic #define LOGFILE "/usr/adm/gamelog" 34*32216Sbostic #endif 35*32216Sbostic 36*32216Sbostic static struct tm *ct; /* current time structure */ 37*32216Sbostic static time_t now; /* current time value */ 38*32216Sbostic static double maxload = -1; /* max load for game */ 39*32216Sbostic static int maxusers = -1; /* max users for game */ 40*32216Sbostic priority = 0; /* priority game runs at */ 41*32216Sbostic static char *game; /* requested game */ 42*32216Sbostic 43*32216Sbostic typedef struct dow { 44*32216Sbostic char *day; 45*32216Sbostic int start, stop; 46*32216Sbostic } DOW; 47*32216Sbostic 48*32216Sbostic static DOW days[] = { 49*32216Sbostic "sunday", 25, -1, 50*32216Sbostic "monday", 25, -1, 51*32216Sbostic "tuesday", 25, -1, 52*32216Sbostic "wednesday", 25, -1, 53*32216Sbostic "thursday", 25, -1, 54*32216Sbostic "friday", 25, -1, 55*32216Sbostic "saturday", 25, -1, 56*32216Sbostic 0, 0, 0, 57*32216Sbostic }; 58*32216Sbostic 59*32216Sbostic main(argc, argv) 60*32216Sbostic int argc; 61*32216Sbostic char **argv; 62*32216Sbostic { 63*32216Sbostic FILE *fp; 64*32216Sbostic char *C, *hour(), *rindex(); 65*32216Sbostic struct tm *localtime(); 66*32216Sbostic time_t time(); 67*32216Sbostic double load(); 68*32216Sbostic 69*32216Sbostic nogamefile(); 70*32216Sbostic 71*32216Sbostic if (argc == 1) { 72*32216Sbostic fputs("dm: game\n", stderr); 73*32216Sbostic exit(1); 74*32216Sbostic } 75*32216Sbostic 76*32216Sbostic if (!(fp = fopen(CONTROL, "r"))) { 77*32216Sbostic fprintf(stderr, "dm: unable to read %s.\n", CONTROL); 78*32216Sbostic exit(1); 79*32216Sbostic } 80*32216Sbostic 81*32216Sbostic read_days(fp); 82*32216Sbostic (void)time(&now); 83*32216Sbostic ct = localtime(&now); 84*32216Sbostic if (ct->tm_hour >= days[ct->tm_wday].start && ct->tm_hour <= days[ct->tm_wday].stop) { 85*32216Sbostic fprintf(stderr, "dm: Sorry, games are only available from %s to %s today.\n", hour(days[ct->tm_wday].start), hour(days[ct->tm_wday].stop)); 86*32216Sbostic exit(0); 87*32216Sbostic } 88*32216Sbostic 89*32216Sbostic ++argv; 90*32216Sbostic game = (C = rindex(*argv, '/')) ? ++C : *argv; 91*32216Sbostic 92*32216Sbostic read_games(fp); 93*32216Sbostic if (maxusers >= 0 && maxusers <= users()) { 94*32216Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 95*32216Sbostic exit(0); 96*32216Sbostic } 97*32216Sbostic if (maxload >= 0 && maxload < load()) { 98*32216Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 99*32216Sbostic exit(0); 100*32216Sbostic } 101*32216Sbostic (void)fclose(fp); 102*32216Sbostic 103*32216Sbostic #ifdef LOG 104*32216Sbostic logfile(); 105*32216Sbostic #endif 106*32216Sbostic play(argv); 107*32216Sbostic } 108*32216Sbostic 109*32216Sbostic /* 110*32216Sbostic * play -- 111*32216Sbostic * play the game 112*32216Sbostic */ 113*32216Sbostic static 114*32216Sbostic play(args) 115*32216Sbostic char **args; 116*32216Sbostic { 117*32216Sbostic uid_t uid; 118*32216Sbostic gid_t gid; 119*32216Sbostic 120*32216Sbostic if (chdir(GAMEHIDE)) { 121*32216Sbostic perror("dm: chdir"); 122*32216Sbostic exit(1); 123*32216Sbostic } 124*32216Sbostic if (priority && setpriority(PRIO_PROCESS, 0, priority) < 0) 125*32216Sbostic fputs("dm: unable to set priority!\n", stderr); 126*32216Sbostic uid = getuid(); 127*32216Sbostic setreuid(uid, uid); 128*32216Sbostic gid = getgid(); 129*32216Sbostic setregid(gid, gid); 130*32216Sbostic execv(game, args); 131*32216Sbostic fprintf(stderr, "dm: can't find %s.\n", game); 132*32216Sbostic exit(1); 133*32216Sbostic } 134*32216Sbostic 135*32216Sbostic /* 136*32216Sbostic * read_days -- 137*32216Sbostic * read through days listed in the control file 138*32216Sbostic */ 139*32216Sbostic static 140*32216Sbostic read_days(fp) 141*32216Sbostic register FILE *fp; 142*32216Sbostic { 143*32216Sbostic register DOW *dp; 144*32216Sbostic char lbuf[BUFSIZ], f1[20], f2[20], f3[20]; 145*32216Sbostic 146*32216Sbostic while (fgets(lbuf, sizeof(lbuf), fp)) { 147*32216Sbostic if (lbuf[0] == '\n' || lbuf[0] == '#') 148*32216Sbostic continue; 149*32216Sbostic /* special line separates days from game names */ 150*32216Sbostic if (lbuf[0] == '%' && lbuf[1] == '%') 151*32216Sbostic return; 152*32216Sbostic if (sscanf(lbuf, "%s%s%s\n", f1, f2, f3) != 3) 153*32216Sbostic continue; 154*32216Sbostic for (dp = days; dp->day; ++dp) 155*32216Sbostic if (dp->start <= 0 && !strcasecmp(dp->day, f1)) { 156*32216Sbostic if (isdigit(*f2)) 157*32216Sbostic dp->start = atoi(f2); 158*32216Sbostic if (isdigit(*f3)) 159*32216Sbostic dp->stop = atoi(f3); 160*32216Sbostic break; 161*32216Sbostic } 162*32216Sbostic } 163*32216Sbostic } 164*32216Sbostic 165*32216Sbostic /* 166*32216Sbostic * read_games -- 167*32216Sbostic * read through games listed in the control file 168*32216Sbostic */ 169*32216Sbostic static 170*32216Sbostic read_games(fp) 171*32216Sbostic register FILE *fp; 172*32216Sbostic { 173*32216Sbostic register char *C; 174*32216Sbostic char lbuf[BUFSIZ], f1[20], f2[20], f3[20]; 175*32216Sbostic double atof(); 176*32216Sbostic 177*32216Sbostic while (fgets(lbuf, sizeof(lbuf), fp)) { 178*32216Sbostic if (lbuf[0] == '\n' || lbuf[0] == '#') 179*32216Sbostic continue; 180*32216Sbostic for (C = lbuf; *C && !isspace(*C); ++C); 181*32216Sbostic *C = '\0'; 182*32216Sbostic if (!strcmp(game, lbuf) || !strcasecmp("default", lbuf)) { 183*32216Sbostic if (sscanf(++C, "%s%s%s\n", f1, f2, f3) != 3) 184*32216Sbostic break; 185*32216Sbostic if (isdigit(*f1)) 186*32216Sbostic maxload = atof(f1); 187*32216Sbostic if (isdigit(*f2)) 188*32216Sbostic maxusers = atoi(f2); 189*32216Sbostic if (isdigit(*f3) || *f3 == '-' || *f3 == '+') 190*32216Sbostic priority = atoi(f3); 191*32216Sbostic break; 192*32216Sbostic } 193*32216Sbostic } 194*32216Sbostic } 195*32216Sbostic 196*32216Sbostic static struct nlist nl[] = { 197*32216Sbostic { "_avenrun" }, 198*32216Sbostic #define X_AVENRUN 0 199*32216Sbostic { "" }, 200*32216Sbostic }; 201*32216Sbostic 202*32216Sbostic /* 203*32216Sbostic * load -- 204*32216Sbostic * return 15 minute load average 205*32216Sbostic */ 206*32216Sbostic static double 207*32216Sbostic load() 208*32216Sbostic { 209*32216Sbostic double avenrun[3]; 210*32216Sbostic int kmem; 211*32216Sbostic long lseek(); 212*32216Sbostic 213*32216Sbostic if (nlist("/vmunix", nl)) { 214*32216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 215*32216Sbostic exit(1); 216*32216Sbostic } 217*32216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 218*32216Sbostic perror("dm: /dev/kmem"); 219*32216Sbostic exit(1); 220*32216Sbostic } 221*32216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 222*32216Sbostic (void)read(kmem, avenrun, sizeof(avenrun)); 223*32216Sbostic return(avenrun[2]); 224*32216Sbostic } 225*32216Sbostic 226*32216Sbostic /* 227*32216Sbostic * users -- 228*32216Sbostic * return current number of users 229*32216Sbostic */ 230*32216Sbostic static 231*32216Sbostic users() 232*32216Sbostic { 233*32216Sbostic register int nusers, 234*32216Sbostic utmp; 235*32216Sbostic struct utmp buf; 236*32216Sbostic 237*32216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 238*32216Sbostic perror("dm: /etc/utmp"); 239*32216Sbostic exit(1); 240*32216Sbostic } 241*32216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 242*32216Sbostic if (buf.ut_name[0] != '\0') 243*32216Sbostic ++nusers; 244*32216Sbostic return(nusers); 245*32216Sbostic } 246*32216Sbostic 247*32216Sbostic /* 248*32216Sbostic * nogamefile -- 249*32216Sbostic * if the file NOGAMING exists, no games allowed. 250*32216Sbostic * file may also contain a message for the user. 251*32216Sbostic */ 252*32216Sbostic static 253*32216Sbostic nogamefile() 254*32216Sbostic { 255*32216Sbostic register int fd, n; 256*32216Sbostic char buf[BUFSIZ]; 257*32216Sbostic 258*32216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 259*32216Sbostic #define MESG "Sorry, no games right now.\n\n" 260*32216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 261*32216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 262*32216Sbostic (void)write(2, buf, n); 263*32216Sbostic exit(1); 264*32216Sbostic } 265*32216Sbostic } 266*32216Sbostic 267*32216Sbostic /* 268*32216Sbostic * hour -- 269*32216Sbostic * print out the hour in human form 270*32216Sbostic */ 271*32216Sbostic static char * 272*32216Sbostic hour(h) 273*32216Sbostic int h; 274*32216Sbostic { 275*32216Sbostic static char buf[20]; 276*32216Sbostic 277*32216Sbostic if (!h) 278*32216Sbostic return("midnight"); 279*32216Sbostic if (h == 12) 280*32216Sbostic return("noon"); 281*32216Sbostic if (h < 12) 282*32216Sbostic (void)sprintf(buf, "%d pm", h - 12); 283*32216Sbostic else 284*32216Sbostic (void)sprintf(buf, "%d am", h); 285*32216Sbostic return(buf); 286*32216Sbostic } 287*32216Sbostic 288*32216Sbostic #ifdef LOG 289*32216Sbostic static 290*32216Sbostic logfile() 291*32216Sbostic { 292*32216Sbostic struct passwd *pw, *getpwuid(); 293*32216Sbostic FILE *lp; 294*32216Sbostic uid_t uid; 295*32216Sbostic int lock_cnt; 296*32216Sbostic char *ctime(), *ttyname(); 297*32216Sbostic 298*32216Sbostic if (lp = fopen(LOGFILE, "a")) { 299*32216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 300*32216Sbostic if (!flock(fileno(lp), LOCK_EX)) 301*32216Sbostic break; 302*32216Sbostic if (lock_cnt == 4) { 303*32216Sbostic perror("dm: log lock"); 304*32216Sbostic (void)fclose(lp); 305*32216Sbostic return; 306*32216Sbostic } 307*32216Sbostic sleep((u_int)1); 308*32216Sbostic } 309*32216Sbostic if (pw = getpwuid(uid = getuid())) 310*32216Sbostic fputs(pw->pw_name, lp); 311*32216Sbostic else 312*32216Sbostic fprintf(lp, "%u", uid); 313*32216Sbostic fprintf(lp, "\t%s\t%s\t%s", game, ttyname(0), ctime(&now)); 314*32216Sbostic (void)fclose(lp); 315*32216Sbostic (void)flock(fileno(lp), LOCK_UN); 316*32216Sbostic } 317*32216Sbostic } 318*32216Sbostic #endif 319