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*32371Sbostic static char sccsid[] = "@(#)dm.c 5.4 (Berkeley) 10/08/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" 2832245Sbostic #define NOGAMING "/usr/games/nogames" 2932245Sbostic #define CONTROL "/usr/games/dm.config" 3032216Sbostic #ifdef LOG 3132245Sbostic #define LOGFILE "/usr/adm/dm.log" 3232216Sbostic #endif 3332216Sbostic 3432216Sbostic static time_t now; /* current time value */ 3532227Sbostic static int priority = 0; /* priority game runs at */ 3632227Sbostic static char *game, /* requested game */ 3732227Sbostic *gametty; /* from tty? */ 3832216Sbostic 3932216Sbostic main(argc, argv) 4032216Sbostic int argc; 4132216Sbostic char **argv; 4232216Sbostic { 43*32371Sbostic char *cp, *rindex(), *ttyname(); 44*32371Sbostic time_t time(); 4532216Sbostic 4632216Sbostic nogamefile(); 47*32371Sbostic game = (cp = rindex(*argv, '/')) ? ++cp : *argv; 4832216Sbostic 49*32371Sbostic if (!strcmp(game, "dm")) 5032227Sbostic exit(0); 5132216Sbostic 52*32371Sbostic gametty = ttyname(0); 53*32371Sbostic (void)time(&now); 54*32371Sbostic read_config(); 5532216Sbostic 5632216Sbostic #ifdef LOG 5732216Sbostic logfile(); 5832216Sbostic #endif 5932216Sbostic play(argv); 60*32371Sbostic /*NOTREACHED*/ 6132216Sbostic } 6232216Sbostic 6332216Sbostic /* 6432216Sbostic * play -- 6532216Sbostic * play the game 6632216Sbostic */ 6732216Sbostic static 6832216Sbostic play(args) 6932216Sbostic char **args; 7032216Sbostic { 7132216Sbostic if (chdir(GAMEHIDE)) { 7232216Sbostic perror("dm: chdir"); 7332216Sbostic exit(1); 7432216Sbostic } 75*32371Sbostic if (priority > 0) /* < 0 requires root */ 76*32371Sbostic (void)setpriority(PRIO_PROCESS, 0, priority); 7732227Sbostic setgid(getgid()); /* we run setgid kmem; lose it */ 7832216Sbostic execv(game, args); 7932227Sbostic perror("dm"); 8032216Sbostic exit(1); 8132216Sbostic } 8232216Sbostic 8332216Sbostic /* 84*32371Sbostic * read_config -- 85*32371Sbostic * read through config file, looking for key words. 8632216Sbostic */ 8732216Sbostic static 88*32371Sbostic read_config() 8932216Sbostic { 90*32371Sbostic FILE *cfp; 91*32371Sbostic char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40]; 92*32371Sbostic 93*32371Sbostic if (!(cfp = fopen(CONTROL, "r"))) { 94*32371Sbostic fprintf(stderr, "dm: unable to read %s.\n", CONTROL); 95*32371Sbostic exit(1); 96*32371Sbostic } 97*32371Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) 98*32371Sbostic switch(*lbuf) { 99*32371Sbostic case 'b': /* badtty */ 100*32371Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 101*32371Sbostic strcasecmp(f1, "badtty")) 102*32371Sbostic break; 103*32371Sbostic c_tty(f2); 104*32371Sbostic break; 105*32371Sbostic case 'g': /* game */ 106*32371Sbostic if (sscanf(lbuf, "%s%s%s%s%s", 107*32371Sbostic f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 108*32371Sbostic break; 109*32371Sbostic c_game(f2, f3, f4, f5); 110*32371Sbostic break; 111*32371Sbostic case 't': /* time */ 112*32371Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 113*32371Sbostic strcasecmp(f1, "time")) 114*32371Sbostic break; 115*32371Sbostic c_day(f2, f3, f4); 116*32371Sbostic } 117*32371Sbostic (void)fclose(cfp); 118*32371Sbostic } 119*32371Sbostic 120*32371Sbostic /* 121*32371Sbostic * c_day -- 122*32371Sbostic * if day is today, see if okay to play 123*32371Sbostic */ 124*32371Sbostic static 125*32371Sbostic c_day(s_day, s_start, s_stop) 126*32371Sbostic char *s_day, *s_start, *s_stop; 127*32371Sbostic { 12832227Sbostic static char *days[] = { 12932227Sbostic "sunday", "monday", "tuesday", "wednesday", 13032227Sbostic "thursday", "friday", "saturday", 13132227Sbostic }; 132*32371Sbostic static struct tm *ct; 13332227Sbostic int start, stop; 13432216Sbostic 135*32371Sbostic if (!ct) 136*32371Sbostic ct = localtime(&now); 137*32371Sbostic if (strcasecmp(s_day, days[ct->tm_wday])) 138*32371Sbostic return; 139*32371Sbostic if (!isdigit(*s_start) || !isdigit(*s_stop)) 140*32371Sbostic return; 141*32371Sbostic start = atoi(s_start); 142*32371Sbostic stop = atoi(s_stop); 143*32371Sbostic if (ct->tm_hour >= start && ct->tm_hour <= stop) { 144*32371Sbostic fputs("dm: Sorry, games are not available from ", stderr); 145*32371Sbostic hour(start); 146*32371Sbostic fputs(" to ", stderr); 147*32371Sbostic hour(stop); 148*32371Sbostic fputs(" today.\n", stderr); 149*32371Sbostic exit(0); 15032216Sbostic } 15132216Sbostic } 15232216Sbostic 15332216Sbostic /* 154*32371Sbostic * c_tty -- 155*32371Sbostic * decide if this tty can be used for games. 15632227Sbostic */ 15732227Sbostic static 158*32371Sbostic c_tty(tty) 159*32371Sbostic char *tty; 16032227Sbostic { 161*32371Sbostic static int first = 1; 162*32371Sbostic static char *p_tty; 163*32371Sbostic char *rindex(); 16432227Sbostic 165*32371Sbostic if (first) { 166*32371Sbostic p_tty = rindex(gametty, '/'); 167*32371Sbostic first = 0; 16832227Sbostic } 169*32371Sbostic 170*32371Sbostic if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 171*32371Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 172*32371Sbostic exit(0); 173*32371Sbostic } 17432227Sbostic } 17532227Sbostic 17632227Sbostic /* 177*32371Sbostic * c_game -- 178*32371Sbostic * see if game can be played now. 17932216Sbostic */ 18032216Sbostic static 181*32371Sbostic c_game(s_game, s_load, s_users, s_priority) 182*32371Sbostic char *s_game, *s_load, *s_users, *s_priority; 18332216Sbostic { 184*32371Sbostic static int found; 185*32371Sbostic double load(); 18632216Sbostic 187*32371Sbostic if (found) 188*32371Sbostic return; 189*32371Sbostic if (strcmp(game, s_game) && strcasecmp("default", s_game)) 190*32371Sbostic return; 191*32371Sbostic ++found; 192*32371Sbostic if (isdigit(*s_load) && atoi(s_load) < load()) { 193*32371Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 194*32371Sbostic exit(0); 19532216Sbostic } 196*32371Sbostic if (isdigit(*s_users) && atoi(s_users) <= users()) { 197*32371Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 198*32371Sbostic exit(0); 199*32371Sbostic } 200*32371Sbostic if (isdigit(*s_priority)) 201*32371Sbostic priority = atoi(s_priority); 20232216Sbostic } 20332216Sbostic 20432216Sbostic static struct nlist nl[] = { 20532216Sbostic { "_avenrun" }, 20632216Sbostic #define X_AVENRUN 0 20732216Sbostic { "" }, 20832216Sbostic }; 20932216Sbostic 21032216Sbostic /* 21132216Sbostic * load -- 21232216Sbostic * return 15 minute load average 21332216Sbostic */ 21432216Sbostic static double 21532216Sbostic load() 21632216Sbostic { 21732216Sbostic double avenrun[3]; 21832216Sbostic int kmem; 21932216Sbostic long lseek(); 22032216Sbostic 22132216Sbostic if (nlist("/vmunix", nl)) { 22232216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 22332216Sbostic exit(1); 22432216Sbostic } 22532216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 22632216Sbostic perror("dm: /dev/kmem"); 22732216Sbostic exit(1); 22832216Sbostic } 22932216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 230*32371Sbostic (void)read(kmem, (char *)avenrun, sizeof(avenrun)); 23132216Sbostic return(avenrun[2]); 23232216Sbostic } 23332216Sbostic 23432216Sbostic /* 23532216Sbostic * users -- 23632216Sbostic * return current number of users 237*32371Sbostic * todo: check idle time; if idle more than X minutes, don't 238*32371Sbostic * count them. 23932216Sbostic */ 24032216Sbostic static 24132216Sbostic users() 24232216Sbostic { 24332216Sbostic register int nusers, 24432216Sbostic utmp; 24532216Sbostic struct utmp buf; 24632216Sbostic 24732216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 24832216Sbostic perror("dm: /etc/utmp"); 24932216Sbostic exit(1); 25032216Sbostic } 25132216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 25232216Sbostic if (buf.ut_name[0] != '\0') 25332216Sbostic ++nusers; 25432216Sbostic return(nusers); 25532216Sbostic } 25632216Sbostic 25732216Sbostic /* 25832216Sbostic * nogamefile -- 25932216Sbostic * if the file NOGAMING exists, no games allowed. 26032216Sbostic * file may also contain a message for the user. 26132216Sbostic */ 26232216Sbostic static 26332216Sbostic nogamefile() 26432216Sbostic { 26532216Sbostic register int fd, n; 26632216Sbostic char buf[BUFSIZ]; 26732216Sbostic 26832216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 26932216Sbostic #define MESG "Sorry, no games right now.\n\n" 27032216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 27132216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 27232216Sbostic (void)write(2, buf, n); 27332216Sbostic exit(1); 27432216Sbostic } 27532216Sbostic } 27632216Sbostic 27732216Sbostic /* 27832216Sbostic * hour -- 27932216Sbostic * print out the hour in human form 28032216Sbostic */ 28132227Sbostic static 28232216Sbostic hour(h) 28332216Sbostic int h; 28432216Sbostic { 28532227Sbostic switch(h) { 28632227Sbostic case 0: 28732227Sbostic fputs("midnight", stderr); 28832227Sbostic break; 28932227Sbostic case 12: 29032227Sbostic fputs("noon", stderr); 29132227Sbostic break; 29232227Sbostic default: 29332227Sbostic if (h > 12) 29432227Sbostic fprintf(stderr, "%dpm", h - 12); 29532227Sbostic else 29632227Sbostic fprintf(stderr, "%dam", h); 29732227Sbostic } 29832216Sbostic } 29932216Sbostic 30032216Sbostic #ifdef LOG 30132216Sbostic static 30232216Sbostic logfile() 30332216Sbostic { 30432216Sbostic struct passwd *pw, *getpwuid(); 30532216Sbostic FILE *lp; 30632216Sbostic uid_t uid; 30732216Sbostic int lock_cnt; 30832227Sbostic char *ctime(); 30932216Sbostic 31032216Sbostic if (lp = fopen(LOGFILE, "a")) { 31132216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 31232216Sbostic if (!flock(fileno(lp), LOCK_EX)) 31332216Sbostic break; 31432216Sbostic if (lock_cnt == 4) { 31532216Sbostic perror("dm: log lock"); 31632216Sbostic (void)fclose(lp); 31732216Sbostic return; 31832216Sbostic } 31932216Sbostic sleep((u_int)1); 32032216Sbostic } 32132216Sbostic if (pw = getpwuid(uid = getuid())) 32232216Sbostic fputs(pw->pw_name, lp); 32332216Sbostic else 32432216Sbostic fprintf(lp, "%u", uid); 32532227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 32632216Sbostic (void)fclose(lp); 32732216Sbostic (void)flock(fileno(lp), LOCK_UN); 32832216Sbostic } 32932216Sbostic } 33032216Sbostic #endif 331