132216Sbostic /* 232216Sbostic * Copyright (c) 1987 Regents of the University of California. 3*32704Sbostic * All rights reserved. 4*32704Sbostic * 5*32704Sbostic * Redistribution and use in source and binary forms are permitted 6*32704Sbostic * provided that this notice is preserved and that due credit is given 7*32704Sbostic * to the University of California at Berkeley. The name of the University 8*32704Sbostic * may not be used to endorse or promote products derived from this 9*32704Sbostic * software without specific written prior permission. This software 10*32704Sbostic * is provided ``as is'' without express or implied warranty. 1132216Sbostic */ 1232216Sbostic 1332216Sbostic #ifndef lint 1432216Sbostic char copyright[] = 1532216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 1632216Sbostic All rights reserved.\n"; 17*32704Sbostic #endif /* not lint */ 1832216Sbostic 1932216Sbostic #ifndef lint 20*32704Sbostic static char sccsid[] = "@(#)dm.c 5.5 (Berkeley) 11/30/87"; 21*32704Sbostic #endif /* not lint */ 2232216Sbostic 2332216Sbostic #include <sys/param.h> 2432216Sbostic #include <sys/file.h> 2532216Sbostic #include <sys/time.h> 2632216Sbostic #include <sys/resource.h> 2732216Sbostic #include <pwd.h> 2832216Sbostic #include <utmp.h> 2932216Sbostic #include <nlist.h> 3032216Sbostic #include <stdio.h> 3132216Sbostic #include <ctype.h> 3232216Sbostic 3332216Sbostic #define GAMEHIDE "/usr/games/hide" 3432245Sbostic #define NOGAMING "/usr/games/nogames" 3532245Sbostic #define CONTROL "/usr/games/dm.config" 3632216Sbostic #ifdef LOG 3732245Sbostic #define LOGFILE "/usr/adm/dm.log" 3832216Sbostic #endif 3932216Sbostic 4032216Sbostic static time_t now; /* current time value */ 4132227Sbostic static int priority = 0; /* priority game runs at */ 4232227Sbostic static char *game, /* requested game */ 4332227Sbostic *gametty; /* from tty? */ 4432216Sbostic 4532216Sbostic main(argc, argv) 4632216Sbostic int argc; 4732216Sbostic char **argv; 4832216Sbostic { 4932371Sbostic char *cp, *rindex(), *ttyname(); 5032371Sbostic time_t time(); 5132216Sbostic 5232216Sbostic nogamefile(); 5332371Sbostic game = (cp = rindex(*argv, '/')) ? ++cp : *argv; 5432216Sbostic 5532371Sbostic if (!strcmp(game, "dm")) 5632227Sbostic exit(0); 5732216Sbostic 5832371Sbostic gametty = ttyname(0); 5932371Sbostic (void)time(&now); 6032371Sbostic read_config(); 6132216Sbostic 6232216Sbostic #ifdef LOG 6332216Sbostic logfile(); 6432216Sbostic #endif 6532216Sbostic play(argv); 6632371Sbostic /*NOTREACHED*/ 6732216Sbostic } 6832216Sbostic 6932216Sbostic /* 7032216Sbostic * play -- 7132216Sbostic * play the game 7232216Sbostic */ 7332216Sbostic static 7432216Sbostic play(args) 7532216Sbostic char **args; 7632216Sbostic { 7732216Sbostic if (chdir(GAMEHIDE)) { 7832216Sbostic perror("dm: chdir"); 7932216Sbostic exit(1); 8032216Sbostic } 8132371Sbostic if (priority > 0) /* < 0 requires root */ 8232371Sbostic (void)setpriority(PRIO_PROCESS, 0, priority); 8332227Sbostic setgid(getgid()); /* we run setgid kmem; lose it */ 8432216Sbostic execv(game, args); 8532227Sbostic perror("dm"); 8632216Sbostic exit(1); 8732216Sbostic } 8832216Sbostic 8932216Sbostic /* 9032371Sbostic * read_config -- 9132371Sbostic * read through config file, looking for key words. 9232216Sbostic */ 9332216Sbostic static 9432371Sbostic read_config() 9532216Sbostic { 9632371Sbostic FILE *cfp; 9732371Sbostic char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40]; 9832371Sbostic 9932371Sbostic if (!(cfp = fopen(CONTROL, "r"))) { 10032371Sbostic fprintf(stderr, "dm: unable to read %s.\n", CONTROL); 10132371Sbostic exit(1); 10232371Sbostic } 10332371Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) 10432371Sbostic switch(*lbuf) { 10532371Sbostic case 'b': /* badtty */ 10632371Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 10732371Sbostic strcasecmp(f1, "badtty")) 10832371Sbostic break; 10932371Sbostic c_tty(f2); 11032371Sbostic break; 11132371Sbostic case 'g': /* game */ 11232371Sbostic if (sscanf(lbuf, "%s%s%s%s%s", 11332371Sbostic f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 11432371Sbostic break; 11532371Sbostic c_game(f2, f3, f4, f5); 11632371Sbostic break; 11732371Sbostic case 't': /* time */ 11832371Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 11932371Sbostic strcasecmp(f1, "time")) 12032371Sbostic break; 12132371Sbostic c_day(f2, f3, f4); 12232371Sbostic } 12332371Sbostic (void)fclose(cfp); 12432371Sbostic } 12532371Sbostic 12632371Sbostic /* 12732371Sbostic * c_day -- 12832371Sbostic * if day is today, see if okay to play 12932371Sbostic */ 13032371Sbostic static 13132371Sbostic c_day(s_day, s_start, s_stop) 13232371Sbostic char *s_day, *s_start, *s_stop; 13332371Sbostic { 13432227Sbostic static char *days[] = { 13532227Sbostic "sunday", "monday", "tuesday", "wednesday", 13632227Sbostic "thursday", "friday", "saturday", 13732227Sbostic }; 13832371Sbostic static struct tm *ct; 13932227Sbostic int start, stop; 14032216Sbostic 14132371Sbostic if (!ct) 14232371Sbostic ct = localtime(&now); 14332371Sbostic if (strcasecmp(s_day, days[ct->tm_wday])) 14432371Sbostic return; 14532371Sbostic if (!isdigit(*s_start) || !isdigit(*s_stop)) 14632371Sbostic return; 14732371Sbostic start = atoi(s_start); 14832371Sbostic stop = atoi(s_stop); 14932371Sbostic if (ct->tm_hour >= start && ct->tm_hour <= stop) { 15032371Sbostic fputs("dm: Sorry, games are not available from ", stderr); 15132371Sbostic hour(start); 15232371Sbostic fputs(" to ", stderr); 15332371Sbostic hour(stop); 15432371Sbostic fputs(" today.\n", stderr); 15532371Sbostic exit(0); 15632216Sbostic } 15732216Sbostic } 15832216Sbostic 15932216Sbostic /* 16032371Sbostic * c_tty -- 16132371Sbostic * decide if this tty can be used for games. 16232227Sbostic */ 16332227Sbostic static 16432371Sbostic c_tty(tty) 16532371Sbostic char *tty; 16632227Sbostic { 16732371Sbostic static int first = 1; 16832371Sbostic static char *p_tty; 16932371Sbostic char *rindex(); 17032227Sbostic 17132371Sbostic if (first) { 17232371Sbostic p_tty = rindex(gametty, '/'); 17332371Sbostic first = 0; 17432227Sbostic } 17532371Sbostic 17632371Sbostic if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 17732371Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 17832371Sbostic exit(0); 17932371Sbostic } 18032227Sbostic } 18132227Sbostic 18232227Sbostic /* 18332371Sbostic * c_game -- 18432371Sbostic * see if game can be played now. 18532216Sbostic */ 18632216Sbostic static 18732371Sbostic c_game(s_game, s_load, s_users, s_priority) 18832371Sbostic char *s_game, *s_load, *s_users, *s_priority; 18932216Sbostic { 19032371Sbostic static int found; 19132371Sbostic double load(); 19232216Sbostic 19332371Sbostic if (found) 19432371Sbostic return; 19532371Sbostic if (strcmp(game, s_game) && strcasecmp("default", s_game)) 19632371Sbostic return; 19732371Sbostic ++found; 19832371Sbostic if (isdigit(*s_load) && atoi(s_load) < load()) { 19932371Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 20032371Sbostic exit(0); 20132216Sbostic } 20232371Sbostic if (isdigit(*s_users) && atoi(s_users) <= users()) { 20332371Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 20432371Sbostic exit(0); 20532371Sbostic } 20632371Sbostic if (isdigit(*s_priority)) 20732371Sbostic priority = atoi(s_priority); 20832216Sbostic } 20932216Sbostic 21032216Sbostic static struct nlist nl[] = { 21132216Sbostic { "_avenrun" }, 21232216Sbostic #define X_AVENRUN 0 21332216Sbostic { "" }, 21432216Sbostic }; 21532216Sbostic 21632216Sbostic /* 21732216Sbostic * load -- 21832216Sbostic * return 15 minute load average 21932216Sbostic */ 22032216Sbostic static double 22132216Sbostic load() 22232216Sbostic { 22332216Sbostic double avenrun[3]; 22432216Sbostic int kmem; 22532216Sbostic long lseek(); 22632216Sbostic 22732216Sbostic if (nlist("/vmunix", nl)) { 22832216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 22932216Sbostic exit(1); 23032216Sbostic } 23132216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 23232216Sbostic perror("dm: /dev/kmem"); 23332216Sbostic exit(1); 23432216Sbostic } 23532216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 23632371Sbostic (void)read(kmem, (char *)avenrun, sizeof(avenrun)); 23732216Sbostic return(avenrun[2]); 23832216Sbostic } 23932216Sbostic 24032216Sbostic /* 24132216Sbostic * users -- 24232216Sbostic * return current number of users 24332371Sbostic * todo: check idle time; if idle more than X minutes, don't 24432371Sbostic * count them. 24532216Sbostic */ 24632216Sbostic static 24732216Sbostic users() 24832216Sbostic { 24932216Sbostic register int nusers, 25032216Sbostic utmp; 25132216Sbostic struct utmp buf; 25232216Sbostic 25332216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 25432216Sbostic perror("dm: /etc/utmp"); 25532216Sbostic exit(1); 25632216Sbostic } 25732216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 25832216Sbostic if (buf.ut_name[0] != '\0') 25932216Sbostic ++nusers; 26032216Sbostic return(nusers); 26132216Sbostic } 26232216Sbostic 26332216Sbostic /* 26432216Sbostic * nogamefile -- 26532216Sbostic * if the file NOGAMING exists, no games allowed. 26632216Sbostic * file may also contain a message for the user. 26732216Sbostic */ 26832216Sbostic static 26932216Sbostic nogamefile() 27032216Sbostic { 27132216Sbostic register int fd, n; 27232216Sbostic char buf[BUFSIZ]; 27332216Sbostic 27432216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 27532216Sbostic #define MESG "Sorry, no games right now.\n\n" 27632216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 27732216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 27832216Sbostic (void)write(2, buf, n); 27932216Sbostic exit(1); 28032216Sbostic } 28132216Sbostic } 28232216Sbostic 28332216Sbostic /* 28432216Sbostic * hour -- 28532216Sbostic * print out the hour in human form 28632216Sbostic */ 28732227Sbostic static 28832216Sbostic hour(h) 28932216Sbostic int h; 29032216Sbostic { 29132227Sbostic switch(h) { 29232227Sbostic case 0: 29332227Sbostic fputs("midnight", stderr); 29432227Sbostic break; 29532227Sbostic case 12: 29632227Sbostic fputs("noon", stderr); 29732227Sbostic break; 29832227Sbostic default: 29932227Sbostic if (h > 12) 30032227Sbostic fprintf(stderr, "%dpm", h - 12); 30132227Sbostic else 30232227Sbostic fprintf(stderr, "%dam", h); 30332227Sbostic } 30432216Sbostic } 30532216Sbostic 30632216Sbostic #ifdef LOG 30732216Sbostic static 30832216Sbostic logfile() 30932216Sbostic { 31032216Sbostic struct passwd *pw, *getpwuid(); 31132216Sbostic FILE *lp; 31232216Sbostic uid_t uid; 31332216Sbostic int lock_cnt; 31432227Sbostic char *ctime(); 31532216Sbostic 31632216Sbostic if (lp = fopen(LOGFILE, "a")) { 31732216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 31832216Sbostic if (!flock(fileno(lp), LOCK_EX)) 31932216Sbostic break; 32032216Sbostic if (lock_cnt == 4) { 32132216Sbostic perror("dm: log lock"); 32232216Sbostic (void)fclose(lp); 32332216Sbostic return; 32432216Sbostic } 32532216Sbostic sleep((u_int)1); 32632216Sbostic } 32732216Sbostic if (pw = getpwuid(uid = getuid())) 32832216Sbostic fputs(pw->pw_name, lp); 32932216Sbostic else 33032216Sbostic fprintf(lp, "%u", uid); 33132227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 33232216Sbostic (void)fclose(lp); 33332216Sbostic (void)flock(fileno(lp), LOCK_UN); 33432216Sbostic } 33532216Sbostic } 33632216Sbostic #endif 337