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 632704Sbostic * provided that this notice is preserved and that due credit is given 732704Sbostic * to the University of California at Berkeley. The name of the University 832704Sbostic * may not be used to endorse or promote products derived from this 932704Sbostic * software without specific written prior permission. This software 1032704Sbostic * 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"; 1732704Sbostic #endif /* not lint */ 1832216Sbostic 1932216Sbostic #ifndef lint 20*33788Sbostic static char sccsid[] = "@(#)dm.c 5.7 (Berkeley) 03/25/88"; 2132704Sbostic #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 static time_t now; /* current time value */ 3432227Sbostic static int priority = 0; /* priority game runs at */ 3532227Sbostic static char *game, /* requested game */ 3632227Sbostic *gametty; /* from tty? */ 3732216Sbostic 38*33788Sbostic /*ARGSUSED*/ 3932216Sbostic main(argc, argv) 40*33788Sbostic int argc; 41*33788Sbostic char **argv; 4232216Sbostic { 43*33788Sbostic char *cp, *rindex(), *ttyname(); 44*33788Sbostic time_t time(); 4532216Sbostic 4632216Sbostic nogamefile(); 4732371Sbostic game = (cp = rindex(*argv, '/')) ? ++cp : *argv; 4832216Sbostic 4932371Sbostic if (!strcmp(game, "dm")) 5032227Sbostic exit(0); 5132216Sbostic 5232371Sbostic gametty = ttyname(0); 5332371Sbostic (void)time(&now); 5432371Sbostic read_config(); 5532216Sbostic #ifdef LOG 5632216Sbostic logfile(); 5732216Sbostic #endif 5832216Sbostic play(argv); 5932371Sbostic /*NOTREACHED*/ 6032216Sbostic } 6132216Sbostic 6232216Sbostic /* 6332216Sbostic * play -- 6432216Sbostic * play the game 6532216Sbostic */ 66*33788Sbostic #define GAMEHIDE "/usr/games/hide/" 6732216Sbostic static 6832216Sbostic play(args) 69*33788Sbostic char **args; 7032216Sbostic { 71*33788Sbostic char pbuf[MAXPATHLEN], *strcpy(); 7233169Sbostic 7333169Sbostic (void)strcpy(pbuf, GAMEHIDE); 7433169Sbostic (void)strcpy(pbuf + sizeof(GAMEHIDE) - 1, game); 7532371Sbostic if (priority > 0) /* < 0 requires root */ 7632371Sbostic (void)setpriority(PRIO_PROCESS, 0, priority); 7732227Sbostic setgid(getgid()); /* we run setgid kmem; lose it */ 7833169Sbostic execv(pbuf, args); 7932227Sbostic perror("dm"); 8032216Sbostic exit(1); 8132216Sbostic } 8232216Sbostic 8332216Sbostic /* 8432371Sbostic * read_config -- 8532371Sbostic * read through config file, looking for key words. 8632216Sbostic */ 87*33788Sbostic #define CONTROL "/usr/games/dm.config" 8832216Sbostic static 8932371Sbostic read_config() 9032216Sbostic { 91*33788Sbostic FILE *cfp; 92*33788Sbostic char *control, *host, *index(), *strcpy(); 93*33788Sbostic char lbuf[BUFSIZ], path[MAXHOSTNAMELEN + sizeof(CONTROL)]; 94*33788Sbostic char f1[40], f2[40], f3[40], f4[40], f5[40]; 9532371Sbostic 96*33788Sbostic host = &path[sizeof(CONTROL)]; 97*33788Sbostic if (gethostname(host, MAXHOSTNAMELEN)) { 98*33788Sbostic perror("dm: gethostname"); 9932371Sbostic exit(1); 10032371Sbostic } 101*33788Sbostic (void)strcpy(path, control = CONTROL); 102*33788Sbostic host[-1] = '.'; 103*33788Sbostic if (host = index(host, '.')) 104*33788Sbostic *host = '\0'; 105*33788Sbostic if (!(cfp = fopen(path, "r")) && !(cfp = fopen(control, "r"))) { 106*33788Sbostic fprintf(stderr, "dm: unable to read %s or %s.\n", 107*33788Sbostic path, control); 108*33788Sbostic exit(1); 109*33788Sbostic } 11032371Sbostic while (fgets(lbuf, sizeof(lbuf), cfp)) 11132371Sbostic switch(*lbuf) { 11232371Sbostic case 'b': /* badtty */ 11332371Sbostic if (sscanf(lbuf, "%s%s", f1, f2) != 2 || 11432371Sbostic strcasecmp(f1, "badtty")) 11532371Sbostic break; 11632371Sbostic c_tty(f2); 11732371Sbostic break; 11832371Sbostic case 'g': /* game */ 11932371Sbostic if (sscanf(lbuf, "%s%s%s%s%s", 12032371Sbostic f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game")) 12132371Sbostic break; 12232371Sbostic c_game(f2, f3, f4, f5); 12332371Sbostic break; 12432371Sbostic case 't': /* time */ 12532371Sbostic if (sscanf(lbuf, "%s%s%s%s", f1, f2, f3, f4) != 4 || 12632371Sbostic strcasecmp(f1, "time")) 12732371Sbostic break; 12832371Sbostic c_day(f2, f3, f4); 12932371Sbostic } 13032371Sbostic (void)fclose(cfp); 13132371Sbostic } 13232371Sbostic 13332371Sbostic /* 13432371Sbostic * c_day -- 13532371Sbostic * if day is today, see if okay to play 13632371Sbostic */ 13732371Sbostic static 13832371Sbostic c_day(s_day, s_start, s_stop) 139*33788Sbostic char *s_day, *s_start, *s_stop; 14032371Sbostic { 141*33788Sbostic static char *days[] = { 14232227Sbostic "sunday", "monday", "tuesday", "wednesday", 14332227Sbostic "thursday", "friday", "saturday", 14432227Sbostic }; 145*33788Sbostic static struct tm *ct; 146*33788Sbostic int start, stop; 14732216Sbostic 14832371Sbostic if (!ct) 14932371Sbostic ct = localtime(&now); 15032371Sbostic if (strcasecmp(s_day, days[ct->tm_wday])) 15132371Sbostic return; 15232371Sbostic if (!isdigit(*s_start) || !isdigit(*s_stop)) 15332371Sbostic return; 15432371Sbostic start = atoi(s_start); 15532371Sbostic stop = atoi(s_stop); 15632371Sbostic if (ct->tm_hour >= start && ct->tm_hour <= stop) { 15732371Sbostic fputs("dm: Sorry, games are not available from ", stderr); 15832371Sbostic hour(start); 15932371Sbostic fputs(" to ", stderr); 16032371Sbostic hour(stop); 16132371Sbostic fputs(" today.\n", stderr); 16232371Sbostic exit(0); 16332216Sbostic } 16432216Sbostic } 16532216Sbostic 16632216Sbostic /* 16732371Sbostic * c_tty -- 16832371Sbostic * decide if this tty can be used for games. 16932227Sbostic */ 17032227Sbostic static 17132371Sbostic c_tty(tty) 172*33788Sbostic char *tty; 17332227Sbostic { 174*33788Sbostic static int first = 1; 175*33788Sbostic static char *p_tty; 176*33788Sbostic char *rindex(); 17732227Sbostic 17832371Sbostic if (first) { 17932371Sbostic p_tty = rindex(gametty, '/'); 18032371Sbostic first = 0; 18132227Sbostic } 18232371Sbostic 18332371Sbostic if (!strcmp(gametty, tty) || p_tty && !strcmp(p_tty, tty)) { 18432371Sbostic fprintf(stderr, "dm: Sorry, you may not play games on %s.\n", gametty); 18532371Sbostic exit(0); 18632371Sbostic } 18732227Sbostic } 18832227Sbostic 18932227Sbostic /* 19032371Sbostic * c_game -- 19132371Sbostic * see if game can be played now. 19232216Sbostic */ 19332216Sbostic static 19432371Sbostic c_game(s_game, s_load, s_users, s_priority) 195*33788Sbostic char *s_game, *s_load, *s_users, *s_priority; 19632216Sbostic { 197*33788Sbostic static int found; 198*33788Sbostic double load(); 19932216Sbostic 20032371Sbostic if (found) 20132371Sbostic return; 20232371Sbostic if (strcmp(game, s_game) && strcasecmp("default", s_game)) 20332371Sbostic return; 20432371Sbostic ++found; 20532371Sbostic if (isdigit(*s_load) && atoi(s_load) < load()) { 20632371Sbostic fputs("dm: Sorry, the load average is too high right now.\n", stderr); 20732371Sbostic exit(0); 20832216Sbostic } 20932371Sbostic if (isdigit(*s_users) && atoi(s_users) <= users()) { 21032371Sbostic fputs("dm: Sorry, there are too many users logged on right now.\n", stderr); 21132371Sbostic exit(0); 21232371Sbostic } 21332371Sbostic if (isdigit(*s_priority)) 21432371Sbostic priority = atoi(s_priority); 21532216Sbostic } 21632216Sbostic 217*33788Sbostic static struct nlist nl[] = { 21832216Sbostic { "_avenrun" }, 21932216Sbostic #define X_AVENRUN 0 22032216Sbostic { "" }, 22132216Sbostic }; 22232216Sbostic 22332216Sbostic /* 22432216Sbostic * load -- 22532216Sbostic * return 15 minute load average 22632216Sbostic */ 22732216Sbostic static double 22832216Sbostic load() 22932216Sbostic { 230*33788Sbostic double avenrun[3]; 231*33788Sbostic int kmem; 232*33788Sbostic long lseek(); 23332216Sbostic 23432216Sbostic if (nlist("/vmunix", nl)) { 23532216Sbostic fputs("dm: nlist of /vmunix failed.\n", stderr); 23632216Sbostic exit(1); 23732216Sbostic } 23832216Sbostic if ((kmem = open("/dev/kmem", O_RDONLY, 0)) < 0) { 23932216Sbostic perror("dm: /dev/kmem"); 24032216Sbostic exit(1); 24132216Sbostic } 24232216Sbostic (void)lseek(kmem, (long)nl[X_AVENRUN].n_value, L_SET); 24332371Sbostic (void)read(kmem, (char *)avenrun, sizeof(avenrun)); 24432216Sbostic return(avenrun[2]); 24532216Sbostic } 24632216Sbostic 24732216Sbostic /* 24832216Sbostic * users -- 24932216Sbostic * return current number of users 25032371Sbostic * todo: check idle time; if idle more than X minutes, don't 25132371Sbostic * count them. 25232216Sbostic */ 25332216Sbostic static 25432216Sbostic users() 25532216Sbostic { 256*33788Sbostic register int nusers, utmp; 257*33788Sbostic struct utmp buf; 25832216Sbostic 25932216Sbostic if ((utmp = open("/etc/utmp", O_RDONLY, 0)) < 0) { 26032216Sbostic perror("dm: /etc/utmp"); 26132216Sbostic exit(1); 26232216Sbostic } 26332216Sbostic for (nusers = 0; read(utmp, (char *)&buf, sizeof(struct utmp)) > 0;) 26432216Sbostic if (buf.ut_name[0] != '\0') 26532216Sbostic ++nusers; 26632216Sbostic return(nusers); 26732216Sbostic } 26832216Sbostic 26932216Sbostic /* 27032216Sbostic * nogamefile -- 27132216Sbostic * if the file NOGAMING exists, no games allowed. 27232216Sbostic * file may also contain a message for the user. 27332216Sbostic */ 274*33788Sbostic #define NOGAMING "/usr/games/nogames" 27532216Sbostic static 27632216Sbostic nogamefile() 27732216Sbostic { 278*33788Sbostic register int fd, n; 279*33788Sbostic char buf[BUFSIZ]; 28032216Sbostic 28132216Sbostic if ((fd = open(NOGAMING, O_RDONLY, 0)) >= 0) { 28232216Sbostic #define MESG "Sorry, no games right now.\n\n" 28332216Sbostic (void)write(2, MESG, sizeof(MESG) - 1); 28432216Sbostic while ((n = read(fd, buf, sizeof(buf))) > 0) 28532216Sbostic (void)write(2, buf, n); 28632216Sbostic exit(1); 28732216Sbostic } 28832216Sbostic } 28932216Sbostic 29032216Sbostic /* 29132216Sbostic * hour -- 29232216Sbostic * print out the hour in human form 29332216Sbostic */ 29432227Sbostic static 29532216Sbostic hour(h) 296*33788Sbostic int h; 29732216Sbostic { 29832227Sbostic switch(h) { 29932227Sbostic case 0: 30032227Sbostic fputs("midnight", stderr); 30132227Sbostic break; 30232227Sbostic case 12: 30332227Sbostic fputs("noon", stderr); 30432227Sbostic break; 30532227Sbostic default: 30632227Sbostic if (h > 12) 30732227Sbostic fprintf(stderr, "%dpm", h - 12); 30832227Sbostic else 30932227Sbostic fprintf(stderr, "%dam", h); 31032227Sbostic } 31132216Sbostic } 31232216Sbostic 31332216Sbostic #ifdef LOG 314*33788Sbostic /* 315*33788Sbostic * logfile -- 316*33788Sbostic * log play of game 317*33788Sbostic */ 318*33788Sbostic #define LOGFILE "/usr/adm/dm.log" 31932216Sbostic static 32032216Sbostic logfile() 32132216Sbostic { 322*33788Sbostic struct passwd *pw, *getpwuid(); 323*33788Sbostic FILE *lp; 324*33788Sbostic uid_t uid; 325*33788Sbostic int lock_cnt; 326*33788Sbostic char *ctime(); 32732216Sbostic 32832216Sbostic if (lp = fopen(LOGFILE, "a")) { 32932216Sbostic for (lock_cnt = 0;; ++lock_cnt) { 33032216Sbostic if (!flock(fileno(lp), LOCK_EX)) 33132216Sbostic break; 33232216Sbostic if (lock_cnt == 4) { 33332216Sbostic perror("dm: log lock"); 33432216Sbostic (void)fclose(lp); 33532216Sbostic return; 33632216Sbostic } 33732216Sbostic sleep((u_int)1); 33832216Sbostic } 33932216Sbostic if (pw = getpwuid(uid = getuid())) 34032216Sbostic fputs(pw->pw_name, lp); 34132216Sbostic else 34232216Sbostic fprintf(lp, "%u", uid); 34332227Sbostic fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now)); 34432216Sbostic (void)fclose(lp); 34532216Sbostic (void)flock(fileno(lp), LOCK_UN); 34632216Sbostic } 34732216Sbostic } 348*33788Sbostic #endif /* LOG */ 349