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*39891Sbostic static char sccsid[] = "@(#)dm.c 5.13 (Berkeley) 01/06/90"; 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> 3737412Sbostic #include "pathnames.h" 3832216Sbostic 3932216Sbostic static time_t now; /* current time value */ 4032227Sbostic static int priority = 0; /* priority game runs at */ 4132227Sbostic static char *game, /* requested game */ 4232227Sbostic *gametty; /* from tty? */ 4332216Sbostic 4433788Sbostic /*ARGSUSED*/ 4532216Sbostic main(argc, argv) 4633788Sbostic int argc; 4733788Sbostic char **argv; 4832216Sbostic { 4933788Sbostic char *cp, *rindex(), *ttyname(); 5033788Sbostic 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 #ifdef LOG 6232216Sbostic logfile(); 6332216Sbostic #endif 6432216Sbostic play(argv); 6532371Sbostic /*NOTREACHED*/ 6632216Sbostic } 6732216Sbostic 6832216Sbostic /* 6932216Sbostic * play -- 7032216Sbostic * play the game 7132216Sbostic */ 7232216Sbostic static 7332216Sbostic play(args) 7433788Sbostic char **args; 7532216Sbostic { 7636812Sbostic extern int errno; 7736812Sbostic char pbuf[MAXPATHLEN], *strcpy(), *strerror(); 7833169Sbostic 7937412Sbostic (void)strcpy(pbuf, _PATH_HIDE); 8037412Sbostic (void)strcpy(pbuf + sizeof(_PATH_HIDE) - 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); 8536812Sbostic (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 */ 9332216Sbostic static 9432371Sbostic read_config() 9532216Sbostic { 9633788Sbostic FILE *cfp; 97*39891Sbostic char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40]; 9832371Sbostic 99*39891Sbostic if (!(cfp = fopen(_PATH_CONFIG, "r"))) 10037412Sbostic return; 10132371Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) 10232371Sbostic switch(*lbuf) { 10332371Sbostic case 'b': /* badtty */ 10432371Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 10532371Sbostic strcasecmp(f1, "badtty")) 10632371Sbostic break; 10732371Sbostic c_tty(f2); 10832371Sbostic break; 10932371Sbostic case 'g': /* game */ 11032371Sbostic if (sscanf(lbuf, "%s%s%s%s%s", 11132371Sbostic f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 11232371Sbostic break; 11332371Sbostic c_game(f2, f3, f4, f5); 11432371Sbostic break; 11532371Sbostic case 't': /* time */ 11632371Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 11732371Sbostic strcasecmp(f1, "time")) 11832371Sbostic break; 11932371Sbostic c_day(f2, f3, f4); 12032371Sbostic } 12132371Sbostic (void)fclose(cfp); 12232371Sbostic } 12332371Sbostic 12432371Sbostic /* 12532371Sbostic * c_day -- 12632371Sbostic * if day is today, see if okay to play 12732371Sbostic */ 12832371Sbostic static 12932371Sbostic c_day(s_day, s_start, s_stop) 13033788Sbostic char *s_day, *s_start, *s_stop; 13132371Sbostic { 13233788Sbostic static char *days[] = { 13332227Sbostic "sunday", "monday", "tuesday", "wednesday", 13432227Sbostic "thursday", "friday", "saturday", 13532227Sbostic }; 13633788Sbostic static struct tm *ct; 13733788Sbostic int start, stop; 13832216Sbostic 13932371Sbostic if (!ct) 14032371Sbostic ct = localtime(&now); 14132371Sbostic if (strcasecmp(s_day, days[ct->tm_wday])) 14232371Sbostic return; 14332371Sbostic if (!isdigit(*s_start) || !isdigit(*s_stop)) 14432371Sbostic return; 14532371Sbostic start = atoi(s_start); 14632371Sbostic stop = atoi(s_stop); 14735718Sbostic if (ct->tm_hour >= start && ct->tm_hour < stop) { 14832371Sbostic fputs("dm: Sorry, games are not available from ", stderr); 14932371Sbostic hour(start); 15032371Sbostic fputs(" to ", stderr); 15132371Sbostic hour(stop); 15232371Sbostic fputs(" today.\n", stderr); 15332371Sbostic exit(0); 15432216Sbostic } 15532216Sbostic } 15632216Sbostic 15732216Sbostic /* 15832371Sbostic * c_tty -- 15932371Sbostic * decide if this tty can be used for games. 16032227Sbostic */ 16132227Sbostic static 16232371Sbostic c_tty(tty) 16333788Sbostic char *tty; 16432227Sbostic { 16533788Sbostic static int first = 1; 16633788Sbostic static char *p_tty; 16733788Sbostic char *rindex(); 16832227Sbostic 16932371Sbostic if (first) { 17032371Sbostic p_tty = rindex(gametty, '/'); 17132371Sbostic first = 0; 17232227Sbostic } 17332371Sbostic 17432371Sbostic if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 17532371Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 17632371Sbostic exit(0); 17732371Sbostic } 17832227Sbostic } 17932227Sbostic 18032227Sbostic /* 18132371Sbostic * c_game -- 18232371Sbostic * see if game can be played now. 18332216Sbostic */ 18432216Sbostic static 18532371Sbostic c_game(s_game, s_load, s_users, s_priority) 18633788Sbostic char *s_game, *s_load, *s_users, *s_priority; 18732216Sbostic { 18833788Sbostic static int found; 18933788Sbostic double load(); 19032216Sbostic 19132371Sbostic if (found) 19232371Sbostic return; 19332371Sbostic if (strcmp(game, s_game) && strcasecmp("default", s_game)) 19432371Sbostic return; 19532371Sbostic ++found; 19632371Sbostic if (isdigit(*s_load) && atoi(s_load) < load()) { 19732371Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 19832371Sbostic exit(0); 19932216Sbostic } 20032371Sbostic if (isdigit(*s_users) && atoi(s_users) <= users()) { 20132371Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 20232371Sbostic exit(0); 20332371Sbostic } 20432371Sbostic if (isdigit(*s_priority)) 20532371Sbostic priority = atoi(s_priority); 20632216Sbostic } 20732216Sbostic 20832216Sbostic /* 20932216Sbostic * load -- 21032216Sbostic * return 15 minute load average 21132216Sbostic */ 21232216Sbostic static double 21332216Sbostic load() 21432216Sbostic { 21533788Sbostic double avenrun[3]; 21632216Sbostic 21738197Smckusick if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0) { 21838197Smckusick fputs("dm: getloadavg() failed.\n", stderr); 21932216Sbostic exit(1); 22032216Sbostic } 22132216Sbostic return(avenrun[2]); 22232216Sbostic } 22332216Sbostic 22432216Sbostic /* 22532216Sbostic * users -- 22632216Sbostic * return current number of users 22732371Sbostic * todo: check idle time; if idle more than X minutes, don't 22832371Sbostic * count them. 22932216Sbostic */ 23032216Sbostic static 23132216Sbostic users() 23232216Sbostic { 23333788Sbostic register int nusers, utmp; 23433788Sbostic struct utmp buf; 23532216Sbostic 23632216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 23732216Sbostic perror("dm: /etc/utmp"); 23832216Sbostic exit(1); 23932216Sbostic } 24032216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 24132216Sbostic if (buf.ut_name[0] != '\0') 24232216Sbostic ++nusers; 24332216Sbostic return(nusers); 24432216Sbostic } 24532216Sbostic 24632216Sbostic static 24732216Sbostic nogamefile() 24832216Sbostic { 24933788Sbostic register int fd, n; 25033788Sbostic char buf[BUFSIZ]; 25132216Sbostic 25237412Sbostic if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) { 25332216Sbostic #define MESG "Sorry, no games right now.\n\n" 25432216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 25532216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 25632216Sbostic (void)write(2, buf, n); 25732216Sbostic exit(1); 25832216Sbostic } 25932216Sbostic } 26032216Sbostic 26132216Sbostic /* 26232216Sbostic * hour -- 26332216Sbostic * print out the hour in human form 26432216Sbostic */ 26532227Sbostic static 26632216Sbostic hour(h) 26733788Sbostic int h; 26832216Sbostic { 26932227Sbostic switch(h) { 27032227Sbostic case 0: 27132227Sbostic fputs("midnight", stderr); 27232227Sbostic break; 27332227Sbostic case 12: 27432227Sbostic fputs("noon", stderr); 27532227Sbostic break; 27632227Sbostic default: 27732227Sbostic if (h > 12) 27832227Sbostic fprintf(stderr, "%dpm", h - 12); 27932227Sbostic else 28032227Sbostic fprintf(stderr, "%dam", h); 28132227Sbostic } 28232216Sbostic } 28332216Sbostic 28432216Sbostic #ifdef LOG 28533788Sbostic /* 28633788Sbostic * logfile -- 28733788Sbostic * log play of game 28833788Sbostic */ 28932216Sbostic static 29032216Sbostic logfile() 29132216Sbostic { 29233788Sbostic struct passwd *pw, *getpwuid(); 29333788Sbostic FILE *lp; 29433788Sbostic uid_t uid; 29533788Sbostic int lock_cnt; 29633788Sbostic char *ctime(); 29732216Sbostic 29837412Sbostic if (lp = fopen(_PATH_LOG, "a")) { 29932216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 30032216Sbostic if (!flock(fileno(lp), LOCK_EX)) 30132216Sbostic break; 30232216Sbostic if (lock_cnt == 4) { 30332216Sbostic perror("dm: log lock"); 30432216Sbostic (void)fclose(lp); 30532216Sbostic return; 30632216Sbostic } 30732216Sbostic sleep((u_int)1); 30832216Sbostic } 30932216Sbostic if (pw = getpwuid(uid = getuid())) 31032216Sbostic fputs(pw->pw_name, lp); 31132216Sbostic else 31232216Sbostic fprintf(lp, "%u", uid); 31332227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 31432216Sbostic (void)fclose(lp); 31532216Sbostic (void)flock(fileno(lp), LOCK_UN); 31632216Sbostic } 31732216Sbostic } 31833788Sbostic #endif /* LOG */ 319