132216Sbostic /* 232216Sbostic * Copyright (c) 1987 Regents of the University of California. 332704Sbostic * All rights reserved. 432704Sbostic * 532704Sbostic * Redistribution and use in source and binary forms are permitted 634782Sbostic * provided that the above copyright notice and this paragraph are 734782Sbostic * duplicated in all such forms and that any documentation, 834782Sbostic * advertising materials, and other materials related to such 934782Sbostic * distribution and use acknowledge that the software was developed 1034782Sbostic * by the University of California, Berkeley. The name of the 1134782Sbostic * University may not be used to endorse or promote products derived 1234782Sbostic * from this software without specific prior written permission. 1334782Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434782Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534782Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1632216Sbostic */ 1732216Sbostic 1832216Sbostic #ifndef lint 1932216Sbostic char copyright[] = 2032216Sbostic "@(#) Copyright (c) 1987 Regents of the University of California.\n\ 2132216Sbostic All rights reserved.\n"; 2232704Sbostic #endif /* not lint */ 2332216Sbostic 2432216Sbostic #ifndef lint 25*36812Sbostic static char sccsid[] = "@(#)dm.c 5.10 (Berkeley) 02/16/89"; 2632704Sbostic #endif /* not lint */ 2732216Sbostic 2832216Sbostic #include <sys/param.h> 2932216Sbostic #include <sys/file.h> 3032216Sbostic #include <sys/time.h> 3132216Sbostic #include <sys/resource.h> 3232216Sbostic #include <pwd.h> 3332216Sbostic #include <utmp.h> 3432216Sbostic #include <nlist.h> 3532216Sbostic #include <stdio.h> 3632216Sbostic #include <ctype.h> 3732216Sbostic 3832216Sbostic static time_t now; /* current time value */ 3932227Sbostic static int priority = 0; /* priority game runs at */ 4032227Sbostic static char *game, /* requested game */ 4132227Sbostic *gametty; /* from tty? */ 4232216Sbostic 4333788Sbostic /*ARGSUSED*/ 4432216Sbostic main(argc, argv) 4533788Sbostic int argc; 4633788Sbostic char **argv; 4732216Sbostic { 4833788Sbostic char *cp, *rindex(), *ttyname(); 4933788Sbostic time_t time(); 5032216Sbostic 5132216Sbostic nogamefile(); 5232371Sbostic game = (cp = rindex(*argv, '/')) ? ++cp : *argv; 5332216Sbostic 5432371Sbostic if (!strcmp(game, "dm")) 5532227Sbostic exit(0); 5632216Sbostic 5732371Sbostic gametty = ttyname(0); 5832371Sbostic (void)time(&now); 5932371Sbostic read_config(); 6032216Sbostic #ifdef LOG 6132216Sbostic logfile(); 6232216Sbostic #endif 6332216Sbostic play(argv); 6432371Sbostic /*NOTREACHED*/ 6532216Sbostic } 6632216Sbostic 6732216Sbostic /* 6832216Sbostic * play -- 6932216Sbostic * play the game 7032216Sbostic */ 7133788Sbostic #define GAMEHIDE "/usr/games/hide/" 7232216Sbostic static 7332216Sbostic play(args) 7433788Sbostic char **args; 7532216Sbostic { 76*36812Sbostic extern int errno; 77*36812Sbostic char pbuf[MAXPATHLEN], *strcpy(), *strerror(); 7833169Sbostic 7933169Sbostic (void)strcpy(pbuf, GAMEHIDE); 8033169Sbostic (void)strcpy(pbuf + sizeof(GAMEHIDE) - 1, game); 8132371Sbostic if (priority > 0) /* < 0 requires root */ 8232371Sbostic (void)setpriority(PRIO_PROCESS, 0, priority); 8332227Sbostic setgid(getgid()); /* we run setgid kmem; lose it */ 8433169Sbostic execv(pbuf, args); 85*36812Sbostic (void)fprintf(stderr, "dm: %s: %s\n", pbuf, strerror(errno)); 8632216Sbostic exit(1); 8732216Sbostic } 8832216Sbostic 8932216Sbostic /* 9032371Sbostic * read_config -- 9132371Sbostic * read through config file, looking for key words. 9232216Sbostic */ 9333788Sbostic #define CONTROL "/usr/games/dm.config" 9432216Sbostic static 9532371Sbostic read_config() 9632216Sbostic { 9733788Sbostic FILE *cfp; 9833788Sbostic char *control, *host, *index(), *strcpy(); 9933788Sbostic char lbuf[BUFSIZ], path[MAXHOSTNAMELEN + sizeof(CONTROL)]; 10033788Sbostic char f1[40], f2[40], f3[40], f4[40], f5[40]; 10132371Sbostic 10233788Sbostic host = &path[sizeof(CONTROL)]; 10333788Sbostic if (gethostname(host, MAXHOSTNAMELEN)) { 10433788Sbostic perror("dm: gethostname"); 10532371Sbostic exit(1); 10632371Sbostic } 10733788Sbostic (void)strcpy(path, control = CONTROL); 10833788Sbostic host[-1] = '.'; 10933788Sbostic if (host = index(host, '.')) 11033788Sbostic *host = '\0'; 11133788Sbostic if (!(cfp = fopen(path, "r")) && !(cfp = fopen(control, "r"))) { 11233788Sbostic fprintf(stderr, "dm: unable to read %s or %s.\n", 11333788Sbostic path, control); 11433788Sbostic exit(1); 11533788Sbostic } 11632371Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) 11732371Sbostic switch(*lbuf) { 11832371Sbostic case 'b': /* badtty */ 11932371Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 12032371Sbostic strcasecmp(f1, "badtty")) 12132371Sbostic break; 12232371Sbostic c_tty(f2); 12332371Sbostic break; 12432371Sbostic case 'g': /* game */ 12532371Sbostic if (sscanf(lbuf, "%s%s%s%s%s", 12632371Sbostic f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 12732371Sbostic break; 12832371Sbostic c_game(f2, f3, f4, f5); 12932371Sbostic break; 13032371Sbostic case 't': /* time */ 13132371Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 13232371Sbostic strcasecmp(f1, "time")) 13332371Sbostic break; 13432371Sbostic c_day(f2, f3, f4); 13532371Sbostic } 13632371Sbostic (void)fclose(cfp); 13732371Sbostic } 13832371Sbostic 13932371Sbostic /* 14032371Sbostic * c_day -- 14132371Sbostic * if day is today, see if okay to play 14232371Sbostic */ 14332371Sbostic static 14432371Sbostic c_day(s_day, s_start, s_stop) 14533788Sbostic char *s_day, *s_start, *s_stop; 14632371Sbostic { 14733788Sbostic static char *days[] = { 14832227Sbostic "sunday", "monday", "tuesday", "wednesday", 14932227Sbostic "thursday", "friday", "saturday", 15032227Sbostic }; 15133788Sbostic static struct tm *ct; 15233788Sbostic int start, stop; 15332216Sbostic 15432371Sbostic if (!ct) 15532371Sbostic ct = localtime(&now); 15632371Sbostic if (strcasecmp(s_day, days[ct->tm_wday])) 15732371Sbostic return; 15832371Sbostic if (!isdigit(*s_start) || !isdigit(*s_stop)) 15932371Sbostic return; 16032371Sbostic start = atoi(s_start); 16132371Sbostic stop = atoi(s_stop); 16235718Sbostic if (ct->tm_hour >= start && ct->tm_hour < stop) { 16332371Sbostic fputs("dm: Sorry, games are not available from ", stderr); 16432371Sbostic hour(start); 16532371Sbostic fputs(" to ", stderr); 16632371Sbostic hour(stop); 16732371Sbostic fputs(" today.\n", stderr); 16832371Sbostic exit(0); 16932216Sbostic } 17032216Sbostic } 17132216Sbostic 17232216Sbostic /* 17332371Sbostic * c_tty -- 17432371Sbostic * decide if this tty can be used for games. 17532227Sbostic */ 17632227Sbostic static 17732371Sbostic c_tty(tty) 17833788Sbostic char *tty; 17932227Sbostic { 18033788Sbostic static int first = 1; 18133788Sbostic static char *p_tty; 18233788Sbostic char *rindex(); 18332227Sbostic 18432371Sbostic if (first) { 18532371Sbostic p_tty = rindex(gametty, '/'); 18632371Sbostic first = 0; 18732227Sbostic } 18832371Sbostic 18932371Sbostic if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 19032371Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 19132371Sbostic exit(0); 19232371Sbostic } 19332227Sbostic } 19432227Sbostic 19532227Sbostic /* 19632371Sbostic * c_game -- 19732371Sbostic * see if game can be played now. 19832216Sbostic */ 19932216Sbostic static 20032371Sbostic c_game(s_game, s_load, s_users, s_priority) 20133788Sbostic char *s_game, *s_load, *s_users, *s_priority; 20232216Sbostic { 20333788Sbostic static int found; 20433788Sbostic double load(); 20532216Sbostic 20632371Sbostic if (found) 20732371Sbostic return; 20832371Sbostic if (strcmp(game, s_game) && strcasecmp("default", s_game)) 20932371Sbostic return; 21032371Sbostic ++found; 21132371Sbostic if (isdigit(*s_load) && atoi(s_load) < load()) { 21232371Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 21332371Sbostic exit(0); 21432216Sbostic } 21532371Sbostic if (isdigit(*s_users) && atoi(s_users) <= users()) { 21632371Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 21732371Sbostic exit(0); 21832371Sbostic } 21932371Sbostic if (isdigit(*s_priority)) 22032371Sbostic priority = atoi(s_priority); 22132216Sbostic } 22232216Sbostic 22333788Sbostic static struct nlist nl[] = { 22432216Sbostic { "_avenrun" }, 22532216Sbostic #define X_AVENRUN 0 22632216Sbostic { "" }, 22732216Sbostic }; 22832216Sbostic 22932216Sbostic /* 23032216Sbostic * load -- 23132216Sbostic * return 15 minute load average 23232216Sbostic */ 23332216Sbostic static double 23432216Sbostic load() 23532216Sbostic { 23633788Sbostic double avenrun[3]; 23733788Sbostic int kmem; 23833788Sbostic long lseek(); 23932216Sbostic 24032216Sbostic if (nlist("/vmunix", nl)) { 24132216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 24232216Sbostic exit(1); 24332216Sbostic } 24432216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 24532216Sbostic perror("dm: /dev/kmem"); 24632216Sbostic exit(1); 24732216Sbostic } 24832216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 24932371Sbostic (void)read(kmem, (char *)avenrun, sizeof(avenrun)); 25032216Sbostic return(avenrun[2]); 25132216Sbostic } 25232216Sbostic 25332216Sbostic /* 25432216Sbostic * users -- 25532216Sbostic * return current number of users 25632371Sbostic * todo: check idle time; if idle more than X minutes, don't 25732371Sbostic * count them. 25832216Sbostic */ 25932216Sbostic static 26032216Sbostic users() 26132216Sbostic { 26233788Sbostic register int nusers, utmp; 26333788Sbostic struct utmp buf; 26432216Sbostic 26532216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 26632216Sbostic perror("dm: /etc/utmp"); 26732216Sbostic exit(1); 26832216Sbostic } 26932216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 27032216Sbostic if (buf.ut_name[0] != '\0') 27132216Sbostic ++nusers; 27232216Sbostic return(nusers); 27332216Sbostic } 27432216Sbostic 27532216Sbostic /* 27632216Sbostic * nogamefile -- 27732216Sbostic * if the file NOGAMING exists, no games allowed. 27832216Sbostic * file may also contain a message for the user. 27932216Sbostic */ 28033788Sbostic #define NOGAMING "/usr/games/nogames" 28132216Sbostic static 28232216Sbostic nogamefile() 28332216Sbostic { 28433788Sbostic register int fd, n; 28533788Sbostic char buf[BUFSIZ]; 28632216Sbostic 28732216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 28832216Sbostic #define MESG "Sorry, no games right now.\n\n" 28932216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 29032216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 29132216Sbostic (void)write(2, buf, n); 29232216Sbostic exit(1); 29332216Sbostic } 29432216Sbostic } 29532216Sbostic 29632216Sbostic /* 29732216Sbostic * hour -- 29832216Sbostic * print out the hour in human form 29932216Sbostic */ 30032227Sbostic static 30132216Sbostic hour(h) 30233788Sbostic int h; 30332216Sbostic { 30432227Sbostic switch(h) { 30532227Sbostic case 0: 30632227Sbostic fputs("midnight", stderr); 30732227Sbostic break; 30832227Sbostic case 12: 30932227Sbostic fputs("noon", stderr); 31032227Sbostic break; 31132227Sbostic default: 31232227Sbostic if (h > 12) 31332227Sbostic fprintf(stderr, "%dpm", h - 12); 31432227Sbostic else 31532227Sbostic fprintf(stderr, "%dam", h); 31632227Sbostic } 31732216Sbostic } 31832216Sbostic 31932216Sbostic #ifdef LOG 32033788Sbostic /* 32133788Sbostic * logfile -- 32233788Sbostic * log play of game 32333788Sbostic */ 32433788Sbostic #define LOGFILE "/usr/adm/dm.log" 32532216Sbostic static 32632216Sbostic logfile() 32732216Sbostic { 32833788Sbostic struct passwd *pw, *getpwuid(); 32933788Sbostic FILE *lp; 33033788Sbostic uid_t uid; 33133788Sbostic int lock_cnt; 33233788Sbostic char *ctime(); 33332216Sbostic 33432216Sbostic if (lp = fopen(LOGFILE, "a")) { 33532216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 33632216Sbostic if (!flock(fileno(lp), LOCK_EX)) 33732216Sbostic break; 33832216Sbostic if (lock_cnt == 4) { 33932216Sbostic perror("dm: log lock"); 34032216Sbostic (void)fclose(lp); 34132216Sbostic return; 34232216Sbostic } 34332216Sbostic sleep((u_int)1); 34432216Sbostic } 34532216Sbostic if (pw = getpwuid(uid = getuid())) 34632216Sbostic fputs(pw->pw_name, lp); 34732216Sbostic else 34832216Sbostic fprintf(lp, "%u", uid); 34932227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 35032216Sbostic (void)fclose(lp); 35132216Sbostic (void)flock(fileno(lp), LOCK_UN); 35232216Sbostic } 35332216Sbostic } 35433788Sbostic #endif /* LOG */ 355