132216Sbostic /* 232216Sbostic * Copyright (c) 1987 Regents of the University of California. 332216Sbostic * All rights reserved. The Berkeley software License Agreement 432216Sbostic * specifies the terms and conditions for redistribution. 532216Sbostic */ 632216Sbostic 732216Sbostic #ifndef lint 832216Sbostic char copyright[] = 932216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1032216Sbostic All rights reserved.\n"; 1132216Sbostic #endif not lint 1232216Sbostic 1332216Sbostic #ifndef lint 14*32245Sbostic static char sccsid[] = "@(#)dm.c 5.3 (Berkeley) 09/21/87"; 1532216Sbostic #endif not lint 1632216Sbostic 1732216Sbostic #include <sys/param.h> 1832216Sbostic #include <sys/file.h> 1932216Sbostic #include <sys/time.h> 2032216Sbostic #include <sys/resource.h> 2132216Sbostic #include <pwd.h> 2232216Sbostic #include <utmp.h> 2332216Sbostic #include <nlist.h> 2432216Sbostic #include <stdio.h> 2532216Sbostic #include <ctype.h> 2632216Sbostic 2732216Sbostic #define GAMEHIDE "/usr/games/hide" 28*32245Sbostic #define NOGAMING "/usr/games/nogames" 29*32245Sbostic #define CONTROL "/usr/games/dm.config" 3032216Sbostic #ifdef LOG 31*32245Sbostic #define LOGFILE "/usr/adm/dm.log" 3232216Sbostic #endif 3332216Sbostic 3432227Sbostic static FILE *cfp; 3532216Sbostic static time_t now; /* current time value */ 3632227Sbostic static int priority = 0; /* priority game runs at */ 3732227Sbostic static char *game, /* requested game */ 3832227Sbostic *gametty; /* from tty? */ 3932216Sbostic 4032216Sbostic main(argc, argv) 4132216Sbostic int argc; 4232216Sbostic char **argv; 4332216Sbostic { 4432227Sbostic char *C, *rindex(); 4532216Sbostic double load(); 4632216Sbostic 4732216Sbostic nogamefile(); 4832216Sbostic 4932227Sbostic if (!strcmp(*argv, "dm")) 5032227Sbostic exit(0); 5132216Sbostic 5232227Sbostic if (!(cfp = fopen(CONTROL, "r"))) { 5332216Sbostic fprintf(stderr, "dm: unable to read %s.\n", CONTROL); 5432216Sbostic exit(1); 5532216Sbostic } 5632216Sbostic 5732227Sbostic read_days(); 5832227Sbostic read_ttys(); 5932216Sbostic 6032216Sbostic game = (C = rindex(*argv, '/')) ? ++C : *argv; 6132227Sbostic read_games(); 6232216Sbostic 6332216Sbostic #ifdef LOG 6432216Sbostic logfile(); 6532216Sbostic #endif 6632216Sbostic play(argv); 6732227Sbostic /*NOTREACHED*/ 6832216Sbostic } 6932216Sbostic 7032216Sbostic /* 7132216Sbostic * play -- 7232216Sbostic * play the game 7332216Sbostic */ 7432216Sbostic static 7532216Sbostic play(args) 7632216Sbostic char **args; 7732216Sbostic { 7832216Sbostic if (chdir(GAMEHIDE)) { 7932216Sbostic perror("dm: chdir"); 8032216Sbostic exit(1); 8132216Sbostic } 82*32245Sbostic if (priority > 0 && setpriority(PRIO_PROCESS, 0, priority) < 0) 8332216Sbostic fputs("dm: unable to set priority!\n", stderr); 8432227Sbostic setgid(getgid()); /* we run setgid kmem; lose it */ 8532216Sbostic execv(game, args); 8632227Sbostic perror("dm"); 8732216Sbostic exit(1); 8832216Sbostic } 8932216Sbostic 9032227Sbostic #define lcontrol(buf) (buf[0] == '%' && buf[1] == '%') 9132227Sbostic #define lignore(buf) (buf[0] == '\n' || buf[0] == '#') 9232216Sbostic /* 9332216Sbostic * read_days -- 9432227Sbostic * read through days listed in the control file, decide 9532227Sbostic * if current time is an okay play time. 9632216Sbostic */ 9732216Sbostic static 9832227Sbostic read_days() 9932216Sbostic { 10032227Sbostic static char *days[] = { 10132227Sbostic "sunday", "monday", "tuesday", "wednesday", 10232227Sbostic "thursday", "friday", "saturday", 10332227Sbostic }; 10432227Sbostic struct tm *ct; 10532227Sbostic register char *dp; 10632227Sbostic int start, stop; 10732227Sbostic char lbuf[BUFSIZ], f1[40], f2[40], f3[40]; 10832227Sbostic time_t time(); 10932216Sbostic 11032227Sbostic (void)time(&now); 11132227Sbostic ct = localtime(&now); 11232227Sbostic dp = days[ct->tm_wday]; 11332227Sbostic 11432227Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) { 11532227Sbostic if (lignore(lbuf)) 11632216Sbostic continue; 11732227Sbostic if (lcontrol(lbuf)) 11832216Sbostic return; 11932227Sbostic if (sscanf(lbuf, "%s%s%s", f1, f2, f3) != 3) 12032216Sbostic continue; 12132227Sbostic if (!strcasecmp(dp, f1)) { 12232227Sbostic if (!isdigit(*f2) || !isdigit(*f3)) 12332227Sbostic continue; 12432227Sbostic start = atoi(f2); 12532227Sbostic stop = atoi(f3); 12632227Sbostic if (ct->tm_hour >= start && ct->tm_hour <= stop) { 12732227Sbostic fputs("dm: Sorry, games are not available from ", stderr); 12832227Sbostic hour(start); 12932227Sbostic fputs(" to ", stderr); 13032227Sbostic hour(stop); 13132227Sbostic fputs(" today.\n", stderr); 13232227Sbostic exit(0); 13332216Sbostic } 13432227Sbostic continue; 13532227Sbostic } 13632216Sbostic } 13732216Sbostic } 13832216Sbostic 13932216Sbostic /* 14032227Sbostic * read_ttys -- 14132227Sbostic * read through ttys listed in the control file, decide if this 14232227Sbostic * tty can be used for games. 14332227Sbostic */ 14432227Sbostic static 14532227Sbostic read_ttys() 14632227Sbostic { 14732227Sbostic register char *p_tty; 14832227Sbostic char lbuf[BUFSIZ], f1[40], f2[40], 14932227Sbostic *ttyname(), *rindex(); 15032227Sbostic 15132227Sbostic gametty = ttyname(0); 15232227Sbostic if (p_tty = rindex(gametty, '/')) 15332227Sbostic ++p_tty; 15432227Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) { 15532227Sbostic if (lignore(lbuf)) 15632227Sbostic continue; 15732227Sbostic if (lcontrol(lbuf)) 15832227Sbostic return; 15932227Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2) 16032227Sbostic continue; 16132227Sbostic if (strcasecmp("badtty", f1)) 16232227Sbostic continue; 16332227Sbostic if (!strcmp(gametty, f2) || p_tty && !strcmp(p_tty, f2)) { 16432227Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 16532227Sbostic exit(0); 16632227Sbostic } 16732227Sbostic } 16832227Sbostic } 16932227Sbostic 17032227Sbostic /* 17132216Sbostic * read_games -- 17232227Sbostic * read through games listed in the control file, decide if this 17332227Sbostic * game can be played now. 17432216Sbostic */ 17532216Sbostic static 17632227Sbostic read_games() 17732216Sbostic { 17832227Sbostic char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40]; 17932216Sbostic 18032227Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) { 18132227Sbostic if (lignore(lbuf)) 18232216Sbostic continue; 18332227Sbostic if (lcontrol(lbuf)) 18432227Sbostic return; 18532227Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4) 18632227Sbostic break; 18732227Sbostic if (!strcmp(game, f1) || !strcasecmp("default", f1)) { 18832227Sbostic if (isdigit(*f2) && atoi(f2) < load()) { 18932227Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 19032227Sbostic exit(0); 19132227Sbostic } 19232227Sbostic if (isdigit(*f3) && atoi(f3) <= users()) { 19332227Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 19432227Sbostic exit(0); 19532227Sbostic } 196*32245Sbostic if (isdigit(*f4)) 19732216Sbostic priority = atoi(f3); 19832227Sbostic return; 19932216Sbostic } 20032216Sbostic } 20132216Sbostic } 20232216Sbostic 20332216Sbostic static struct nlist nl[] = { 20432216Sbostic { "_avenrun" }, 20532216Sbostic #define X_AVENRUN 0 20632216Sbostic { "" }, 20732216Sbostic }; 20832216Sbostic 20932216Sbostic /* 21032216Sbostic * load -- 21132216Sbostic * return 15 minute load average 21232216Sbostic */ 21332216Sbostic static double 21432216Sbostic load() 21532216Sbostic { 21632216Sbostic double avenrun[3]; 21732216Sbostic int kmem; 21832216Sbostic long lseek(); 21932216Sbostic 22032216Sbostic if (nlist("/vmunix", nl)) { 22132216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 22232216Sbostic exit(1); 22332216Sbostic } 22432216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 22532216Sbostic perror("dm: /dev/kmem"); 22632216Sbostic exit(1); 22732216Sbostic } 22832216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 22932216Sbostic (void)read(kmem, avenrun, sizeof(avenrun)); 23032216Sbostic return(avenrun[2]); 23132216Sbostic } 23232216Sbostic 23332216Sbostic /* 23432216Sbostic * users -- 23532216Sbostic * return current number of users 23632216Sbostic */ 23732216Sbostic static 23832216Sbostic users() 23932216Sbostic { 24032216Sbostic register int nusers, 24132216Sbostic utmp; 24232216Sbostic struct utmp buf; 24332216Sbostic 24432216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 24532216Sbostic perror("dm: /etc/utmp"); 24632216Sbostic exit(1); 24732216Sbostic } 24832216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 24932216Sbostic if (buf.ut_name[0] != '\0') 25032216Sbostic ++nusers; 25132216Sbostic return(nusers); 25232216Sbostic } 25332216Sbostic 25432216Sbostic /* 25532216Sbostic * nogamefile -- 25632216Sbostic * if the file NOGAMING exists, no games allowed. 25732216Sbostic * file may also contain a message for the user. 25832216Sbostic */ 25932216Sbostic static 26032216Sbostic nogamefile() 26132216Sbostic { 26232216Sbostic register int fd, n; 26332216Sbostic char buf[BUFSIZ]; 26432216Sbostic 26532216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 26632216Sbostic #define MESG "Sorry, no games right now.\n\n" 26732216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 26832216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 26932216Sbostic (void)write(2, buf, n); 27032216Sbostic exit(1); 27132216Sbostic } 27232216Sbostic } 27332216Sbostic 27432216Sbostic /* 27532216Sbostic * hour -- 27632216Sbostic * print out the hour in human form 27732216Sbostic */ 27832227Sbostic static 27932216Sbostic hour(h) 28032216Sbostic int h; 28132216Sbostic { 28232227Sbostic switch(h) { 28332227Sbostic case 0: 28432227Sbostic fputs("midnight", stderr); 28532227Sbostic break; 28632227Sbostic case 12: 28732227Sbostic fputs("noon", stderr); 28832227Sbostic break; 28932227Sbostic default: 29032227Sbostic if (h > 12) 29132227Sbostic fprintf(stderr, "%dpm", h - 12); 29232227Sbostic else 29332227Sbostic fprintf(stderr, "%dam", h); 29432227Sbostic } 29532216Sbostic } 29632216Sbostic 29732216Sbostic #ifdef LOG 29832216Sbostic static 29932216Sbostic logfile() 30032216Sbostic { 30132216Sbostic struct passwd *pw, *getpwuid(); 30232216Sbostic FILE *lp; 30332216Sbostic uid_t uid; 30432216Sbostic int lock_cnt; 30532227Sbostic char *ctime(); 30632216Sbostic 30732216Sbostic if (lp = fopen(LOGFILE, "a")) { 30832216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 30932216Sbostic if (!flock(fileno(lp), LOCK_EX)) 31032216Sbostic break; 31132216Sbostic if (lock_cnt == 4) { 31232216Sbostic perror("dm: log lock"); 31332216Sbostic (void)fclose(lp); 31432216Sbostic return; 31532216Sbostic } 31632216Sbostic sleep((u_int)1); 31732216Sbostic } 31832216Sbostic if (pw = getpwuid(uid = getuid())) 31932216Sbostic fputs(pw->pw_name, lp); 32032216Sbostic else 32132216Sbostic fprintf(lp, "%u", uid); 32232227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 32332216Sbostic (void)fclose(lp); 32432216Sbostic (void)flock(fileno(lp), LOCK_UN); 32532216Sbostic } 32632216Sbostic } 32732216Sbostic #endif 328