Home | History | Annotate | Line # | Download | only in dm
dm.c revision 1.24
      1  1.24     perry /*	$NetBSD: dm.c,v 1.24 2007/12/15 19:44:40 perry Exp $	*/
      2   1.4       cgd 
      3   1.1       cgd /*
      4   1.4       cgd  * Copyright (c) 1987, 1993
      5   1.4       cgd  *	The Regents of the University of California.  All rights reserved.
      6   1.1       cgd  *
      7   1.1       cgd  * Redistribution and use in source and binary forms, with or without
      8   1.1       cgd  * modification, are permitted provided that the following conditions
      9   1.1       cgd  * are met:
     10   1.1       cgd  * 1. Redistributions of source code must retain the above copyright
     11   1.1       cgd  *    notice, this list of conditions and the following disclaimer.
     12   1.1       cgd  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1       cgd  *    notice, this list of conditions and the following disclaimer in the
     14   1.1       cgd  *    documentation and/or other materials provided with the distribution.
     15  1.18       agc  * 3. Neither the name of the University nor the names of its contributors
     16   1.1       cgd  *    may be used to endorse or promote products derived from this software
     17   1.1       cgd  *    without specific prior written permission.
     18   1.1       cgd  *
     19   1.1       cgd  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20   1.1       cgd  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21   1.1       cgd  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22   1.1       cgd  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23   1.1       cgd  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24   1.1       cgd  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25   1.1       cgd  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26   1.1       cgd  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27   1.1       cgd  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28   1.1       cgd  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29   1.1       cgd  * SUCH DAMAGE.
     30   1.1       cgd  */
     31   1.1       cgd 
     32   1.7     lukem #include <sys/cdefs.h>
     33   1.1       cgd #ifndef lint
     34   1.7     lukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
     35   1.7     lukem 	The Regents of the University of California.  All rights reserved.\n");
     36   1.1       cgd #endif /* not lint */
     37   1.1       cgd 
     38   1.1       cgd #ifndef lint
     39   1.4       cgd #if 0
     40   1.4       cgd static char sccsid[] = "@(#)dm.c	8.1 (Berkeley) 5/31/93";
     41   1.4       cgd #else
     42  1.24     perry __RCSID("$NetBSD: dm.c,v 1.24 2007/12/15 19:44:40 perry Exp $");
     43   1.4       cgd #endif
     44   1.1       cgd #endif /* not lint */
     45   1.1       cgd 
     46   1.1       cgd #include <sys/param.h>
     47   1.1       cgd #include <sys/file.h>
     48   1.1       cgd #include <sys/time.h>
     49   1.1       cgd #include <sys/resource.h>
     50   1.4       cgd 
     51   1.7     lukem #include <err.h>
     52   1.4       cgd #include <ctype.h>
     53   1.7     lukem #include <errno.h>
     54   1.1       cgd #include <pwd.h>
     55   1.1       cgd #include <stdio.h>
     56   1.7     lukem #include <stdlib.h>
     57   1.2   mycroft #include <string.h>
     58   1.4       cgd #include <time.h>
     59   1.4       cgd #include <unistd.h>
     60   1.4       cgd 
     61  1.17  christos #include "utmpentry.h"
     62   1.1       cgd #include "pathnames.h"
     63   1.1       cgd 
     64   1.1       cgd static time_t	now;			/* current time value */
     65   1.1       cgd static int	priority = 0;		/* priority game runs at */
     66   1.1       cgd static char	*game,			/* requested game */
     67   1.1       cgd 		*gametty;		/* from tty? */
     68   1.1       cgd 
     69  1.19       jsm void	c_day(const char *, const char *, const char *);
     70  1.19       jsm void	c_game(const char *, const char  *, const char *, const char *);
     71  1.19       jsm void	c_tty(const char *);
     72  1.19       jsm const char *hour(int);
     73  1.19       jsm double	load(void);
     74  1.19       jsm void	nogamefile(void);
     75  1.24     perry void	play(char **) __dead;
     76  1.19       jsm void	read_config(void);
     77  1.19       jsm int	users(void);
     78   1.7     lukem 
     79   1.4       cgd int
     80  1.24     perry main(int argc __unused, char *argv[])
     81   1.1       cgd {
     82   1.4       cgd 	char *cp;
     83   1.1       cgd 
     84   1.1       cgd 	nogamefile();
     85   1.7     lukem 	game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
     86   1.1       cgd 
     87   1.1       cgd 	if (!strcmp(game, "dm"))
     88   1.1       cgd 		exit(0);
     89   1.1       cgd 
     90   1.1       cgd 	gametty = ttyname(0);
     91  1.10   hubertf 	unsetenv("TZ");
     92   1.1       cgd 	(void)time(&now);
     93   1.1       cgd 	read_config();
     94   1.1       cgd #ifdef LOG
     95   1.1       cgd 	logfile();
     96   1.1       cgd #endif
     97   1.1       cgd 	play(argv);
     98   1.1       cgd 	/*NOTREACHED*/
     99   1.9       mrg 	return (0);
    100   1.1       cgd }
    101   1.1       cgd 
    102   1.1       cgd /*
    103   1.1       cgd  * play --
    104   1.1       cgd  *	play the game
    105   1.1       cgd  */
    106   1.7     lukem void
    107  1.22       jmc play(char **args)
    108   1.1       cgd {
    109   1.2   mycroft 	char pbuf[MAXPATHLEN];
    110   1.1       cgd 
    111  1.16  jdolecek 	snprintf(pbuf, sizeof(pbuf), "%s%s", _PATH_HIDE, game);
    112   1.1       cgd 	if (priority > 0)	/* < 0 requires root */
    113   1.1       cgd 		(void)setpriority(PRIO_PROCESS, 0, priority);
    114   1.1       cgd 	execv(pbuf, args);
    115   1.7     lukem 	err(1, "%s", pbuf);
    116   1.1       cgd }
    117   1.1       cgd 
    118   1.1       cgd /*
    119   1.1       cgd  * read_config --
    120   1.1       cgd  *	read through config file, looking for key words.
    121   1.1       cgd  */
    122   1.7     lukem void
    123  1.22       jmc read_config(void)
    124   1.1       cgd {
    125   1.1       cgd 	FILE *cfp;
    126   1.1       cgd 	char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
    127   1.1       cgd 
    128   1.1       cgd 	if (!(cfp = fopen(_PATH_CONFIG, "r")))
    129   1.1       cgd 		return;
    130   1.1       cgd 	while (fgets(lbuf, sizeof(lbuf), cfp))
    131   1.9       mrg 		switch (*lbuf) {
    132   1.1       cgd 		case 'b':		/* badtty */
    133  1.23       dan 			if (sscanf(lbuf, "%39s%39s", f1, f2) != 2 ||
    134   1.1       cgd 			    strcasecmp(f1, "badtty"))
    135   1.1       cgd 				break;
    136   1.1       cgd 			c_tty(f2);
    137   1.1       cgd 			break;
    138   1.1       cgd 		case 'g':		/* game */
    139  1.23       dan 			if (sscanf(lbuf, "%39s%39s%39s%39s%39s",
    140   1.1       cgd 			    f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
    141   1.1       cgd 				break;
    142   1.1       cgd 			c_game(f2, f3, f4, f5);
    143   1.1       cgd 			break;
    144   1.1       cgd 		case 't':		/* time */
    145  1.23       dan 			if (sscanf(lbuf, "%39s%39s%39s%39s", f1, f2, f3, f4) != 4 ||
    146   1.1       cgd 			    strcasecmp(f1, "time"))
    147   1.1       cgd 				break;
    148   1.1       cgd 			c_day(f2, f3, f4);
    149   1.1       cgd 		}
    150   1.1       cgd 	(void)fclose(cfp);
    151   1.1       cgd }
    152   1.1       cgd 
    153   1.1       cgd /*
    154   1.1       cgd  * c_day --
    155   1.1       cgd  *	if day is today, see if okay to play
    156   1.1       cgd  */
    157   1.7     lukem void
    158  1.22       jmc c_day(const char *s_day, const char *s_start, const char *s_stop)
    159   1.1       cgd {
    160  1.12   hubertf 	static const char *const days[] = {
    161   1.1       cgd 		"sunday", "monday", "tuesday", "wednesday",
    162   1.1       cgd 		"thursday", "friday", "saturday",
    163   1.1       cgd 	};
    164   1.1       cgd 	static struct tm *ct;
    165   1.1       cgd 	int start, stop;
    166   1.1       cgd 
    167   1.1       cgd 	if (!ct)
    168   1.1       cgd 		ct = localtime(&now);
    169   1.1       cgd 	if (strcasecmp(s_day, days[ct->tm_wday]))
    170   1.1       cgd 		return;
    171  1.22       jmc 	if (!isdigit((unsigned char)*s_start) ||
    172  1.22       jmc 	    !isdigit((unsigned char)*s_stop))
    173   1.1       cgd 		return;
    174   1.1       cgd 	start = atoi(s_start);
    175   1.1       cgd 	stop = atoi(s_stop);
    176  1.13       jsm 	if (ct->tm_hour >= start && ct->tm_hour < stop) {
    177  1.13       jsm 		if (start == 0 && stop == 24)
    178  1.13       jsm 			errx(0, "Sorry, games are not available today.");
    179  1.13       jsm 		else
    180  1.13       jsm 			errx(0, "Sorry, games are not available from %s to %s today.",
    181  1.13       jsm 			     hour(start), hour(stop));
    182  1.13       jsm 	}
    183   1.1       cgd }
    184   1.1       cgd 
    185   1.1       cgd /*
    186   1.1       cgd  * c_tty --
    187   1.1       cgd  *	decide if this tty can be used for games.
    188   1.1       cgd  */
    189   1.7     lukem void
    190  1.22       jmc c_tty(const char *tty)
    191   1.1       cgd {
    192   1.1       cgd 	static int first = 1;
    193   1.1       cgd 	static char *p_tty;
    194   1.1       cgd 
    195   1.1       cgd 	if (first) {
    196   1.7     lukem 		p_tty = strrchr(gametty, '/');
    197   1.1       cgd 		first = 0;
    198   1.1       cgd 	}
    199   1.1       cgd 
    200   1.7     lukem 	if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
    201   1.7     lukem 		errx(1, "Sorry, you may not play games on %s.", gametty);
    202   1.1       cgd }
    203   1.1       cgd 
    204   1.1       cgd /*
    205   1.1       cgd  * c_game --
    206   1.1       cgd  *	see if game can be played now.
    207   1.1       cgd  */
    208   1.7     lukem void
    209  1.22       jmc c_game(const char *s_game, const char *s_load, const char *s_users,
    210  1.22       jmc        const char *s_priority)
    211   1.1       cgd {
    212   1.1       cgd 	static int found;
    213   1.1       cgd 
    214   1.1       cgd 	if (found)
    215   1.1       cgd 		return;
    216   1.1       cgd 	if (strcmp(game, s_game) && strcasecmp("default", s_game))
    217   1.1       cgd 		return;
    218   1.1       cgd 	++found;
    219  1.21       dsl 	if (isdigit((unsigned char)*s_load) && atoi(s_load) < load())
    220   1.7     lukem 		errx(0, "Sorry, the load average is too high right now.");
    221  1.21       dsl 	if (isdigit((unsigned char)*s_users) && atoi(s_users) <= users())
    222   1.7     lukem 		errx(0, "Sorry, there are too many users logged on right now.");
    223  1.21       dsl 	if (isdigit((unsigned char)*s_priority))
    224   1.1       cgd 		priority = atoi(s_priority);
    225   1.1       cgd }
    226   1.1       cgd 
    227   1.1       cgd /*
    228   1.1       cgd  * load --
    229   1.1       cgd  *	return 15 minute load average
    230   1.1       cgd  */
    231   1.1       cgd double
    232  1.22       jmc load(void)
    233   1.1       cgd {
    234   1.1       cgd 	double avenrun[3];
    235   1.1       cgd 
    236   1.7     lukem 	if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
    237  1.15       jsm 		err(1, "getloadavg() failed");
    238   1.9       mrg 	return (avenrun[2]);
    239   1.1       cgd }
    240   1.1       cgd 
    241   1.1       cgd /*
    242   1.1       cgd  * users --
    243   1.1       cgd  *	return current number of users
    244   1.1       cgd  *	todo: check idle time; if idle more than X minutes, don't
    245   1.1       cgd  *	count them.
    246   1.1       cgd  */
    247   1.7     lukem int
    248  1.22       jmc users(void)
    249   1.1       cgd {
    250  1.17  christos 	static struct utmpentry *ohead = NULL;
    251  1.17  christos 	struct utmpentry *ep;
    252  1.17  christos 	int nusers;
    253  1.17  christos 
    254  1.17  christos 	nusers = getutentries(NULL, &ep);
    255  1.17  christos 	if (ep != ohead) {
    256  1.17  christos 		freeutentries(ep);
    257  1.17  christos 		ohead = ep;
    258  1.17  christos 	}
    259  1.17  christos 	return nusers;
    260   1.1       cgd }
    261   1.1       cgd 
    262   1.7     lukem void
    263  1.22       jmc nogamefile(void)
    264   1.1       cgd {
    265   1.7     lukem 	int fd, n;
    266   1.1       cgd 	char buf[BUFSIZ];
    267   1.1       cgd 
    268   1.1       cgd 	if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
    269   1.1       cgd #define	MESG	"Sorry, no games right now.\n\n"
    270   1.1       cgd 		(void)write(2, MESG, sizeof(MESG) - 1);
    271   1.1       cgd 		while ((n = read(fd, buf, sizeof(buf))) > 0)
    272   1.1       cgd 			(void)write(2, buf, n);
    273   1.1       cgd 		exit(1);
    274   1.1       cgd 	}
    275   1.1       cgd }
    276   1.1       cgd 
    277   1.1       cgd /*
    278   1.1       cgd  * hour --
    279   1.1       cgd  *	print out the hour in human form
    280   1.1       cgd  */
    281   1.7     lukem const char *
    282  1.22       jmc hour(int h)
    283   1.1       cgd {
    284  1.12   hubertf 	static const char *const hours[] = {
    285   1.7     lukem 	    "midnight", "1am", "2am", "3am", "4am", "5am",
    286   1.7     lukem 	    "6am", "7am", "8am", "9am", "10am", "11am",
    287   1.7     lukem 	    "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
    288  1.13       jsm 	    "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
    289   1.7     lukem 
    290  1.13       jsm 	if (h < 0 || h > 24)
    291   1.9       mrg 		return ("BAD TIME");
    292   1.7     lukem 	else
    293   1.9       mrg 		return (hours[h]);
    294   1.1       cgd }
    295   1.1       cgd 
    296   1.1       cgd #ifdef LOG
    297   1.1       cgd /*
    298   1.1       cgd  * logfile --
    299   1.1       cgd  *	log play of game
    300   1.1       cgd  */
    301  1.22       jmc logfile(void)
    302   1.1       cgd {
    303   1.4       cgd 	struct passwd *pw;
    304   1.1       cgd 	FILE *lp;
    305   1.1       cgd 	uid_t uid;
    306   1.1       cgd 	int lock_cnt;
    307   1.1       cgd 
    308   1.1       cgd 	if (lp = fopen(_PATH_LOG, "a")) {
    309   1.1       cgd 		for (lock_cnt = 0;; ++lock_cnt) {
    310   1.1       cgd 			if (!flock(fileno(lp), LOCK_EX))
    311   1.1       cgd 				break;
    312   1.1       cgd 			if (lock_cnt == 4) {
    313   1.7     lukem 				warnx("log lock");
    314   1.1       cgd 				(void)fclose(lp);
    315   1.1       cgd 				return;
    316   1.1       cgd 			}
    317   1.1       cgd 			sleep((u_int)1);
    318   1.1       cgd 		}
    319   1.1       cgd 		if (pw = getpwuid(uid = getuid()))
    320   1.1       cgd 			fputs(pw->pw_name, lp);
    321   1.1       cgd 		else
    322   1.1       cgd 			fprintf(lp, "%u", uid);
    323   1.1       cgd 		fprintf(lp, "\t%s\t%s\t%s", game, gametty, ctime(&now));
    324   1.1       cgd 		(void)fclose(lp);
    325   1.1       cgd 		(void)flock(fileno(lp), LOCK_UN);
    326   1.1       cgd 	}
    327   1.1       cgd }
    328   1.1       cgd #endif /* LOG */
    329