Home | History | Annotate | Line # | Download | only in dm
      1  1.30    rillig /*	$NetBSD: dm.c,v 1.30 2021/05/02 12:50:44 rillig 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.26     lukem __COPYRIGHT("@(#) Copyright (c) 1987, 1993\
     35  1.26     lukem  The Regents of the University of California.  All rights reserved.");
     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.30    rillig __RCSID("$NetBSD: dm.c,v 1.30 2021/05/02 12:50:44 rillig 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.28  dholland static void c_day(const char *, const char *, const char *);
     70  1.28  dholland static void c_game(const char *, const char  *, const char *, const char *);
     71  1.28  dholland static void c_tty(const char *);
     72  1.28  dholland static const char *hour(int);
     73  1.28  dholland static double load(void);
     74  1.28  dholland static void nogamefile(void);
     75  1.28  dholland static void play(char **) __dead;
     76  1.28  dholland static void read_config(void);
     77  1.28  dholland static int users(void);
     78  1.28  dholland 
     79  1.28  dholland #ifdef LOG
     80  1.28  dholland static void logfile(void);
     81  1.28  dholland #endif
     82   1.7     lukem 
     83   1.4       cgd int
     84  1.24     perry main(int argc __unused, char *argv[])
     85   1.1       cgd {
     86   1.4       cgd 	char *cp;
     87   1.1       cgd 
     88   1.1       cgd 	nogamefile();
     89   1.7     lukem 	game = (cp = strrchr(*argv, '/')) ? ++cp : *argv;
     90   1.1       cgd 
     91   1.1       cgd 	if (!strcmp(game, "dm"))
     92   1.1       cgd 		exit(0);
     93   1.1       cgd 
     94   1.1       cgd 	gametty = ttyname(0);
     95  1.10   hubertf 	unsetenv("TZ");
     96   1.1       cgd 	(void)time(&now);
     97   1.1       cgd 	read_config();
     98   1.1       cgd #ifdef LOG
     99   1.1       cgd 	logfile();
    100   1.1       cgd #endif
    101   1.1       cgd 	play(argv);
    102   1.1       cgd 	/*NOTREACHED*/
    103   1.9       mrg 	return (0);
    104   1.1       cgd }
    105   1.1       cgd 
    106   1.1       cgd /*
    107   1.1       cgd  * play --
    108   1.1       cgd  *	play the game
    109   1.1       cgd  */
    110  1.28  dholland static void
    111  1.22       jmc play(char **args)
    112   1.1       cgd {
    113   1.2   mycroft 	char pbuf[MAXPATHLEN];
    114   1.1       cgd 
    115  1.16  jdolecek 	snprintf(pbuf, sizeof(pbuf), "%s%s", _PATH_HIDE, game);
    116   1.1       cgd 	if (priority > 0)	/* < 0 requires root */
    117   1.1       cgd 		(void)setpriority(PRIO_PROCESS, 0, priority);
    118   1.1       cgd 	execv(pbuf, args);
    119   1.7     lukem 	err(1, "%s", pbuf);
    120   1.1       cgd }
    121   1.1       cgd 
    122   1.1       cgd /*
    123   1.1       cgd  * read_config --
    124   1.1       cgd  *	read through config file, looking for key words.
    125   1.1       cgd  */
    126  1.28  dholland static void
    127  1.22       jmc read_config(void)
    128   1.1       cgd {
    129   1.1       cgd 	FILE *cfp;
    130   1.1       cgd 	char lbuf[BUFSIZ], f1[40], f2[40], f3[40], f4[40], f5[40];
    131   1.1       cgd 
    132   1.1       cgd 	if (!(cfp = fopen(_PATH_CONFIG, "r")))
    133   1.1       cgd 		return;
    134   1.1       cgd 	while (fgets(lbuf, sizeof(lbuf), cfp))
    135   1.9       mrg 		switch (*lbuf) {
    136   1.1       cgd 		case 'b':		/* badtty */
    137  1.23       dan 			if (sscanf(lbuf, "%39s%39s", f1, f2) != 2 ||
    138   1.1       cgd 			    strcasecmp(f1, "badtty"))
    139   1.1       cgd 				break;
    140   1.1       cgd 			c_tty(f2);
    141   1.1       cgd 			break;
    142   1.1       cgd 		case 'g':		/* game */
    143  1.23       dan 			if (sscanf(lbuf, "%39s%39s%39s%39s%39s",
    144   1.1       cgd 			    f1, f2, f3, f4, f5) != 5 || strcasecmp(f1, "game"))
    145   1.1       cgd 				break;
    146   1.1       cgd 			c_game(f2, f3, f4, f5);
    147   1.1       cgd 			break;
    148   1.1       cgd 		case 't':		/* time */
    149  1.23       dan 			if (sscanf(lbuf, "%39s%39s%39s%39s", f1, f2, f3, f4) != 4 ||
    150   1.1       cgd 			    strcasecmp(f1, "time"))
    151   1.1       cgd 				break;
    152   1.1       cgd 			c_day(f2, f3, f4);
    153   1.1       cgd 		}
    154   1.1       cgd 	(void)fclose(cfp);
    155   1.1       cgd }
    156   1.1       cgd 
    157   1.1       cgd /*
    158   1.1       cgd  * c_day --
    159   1.1       cgd  *	if day is today, see if okay to play
    160   1.1       cgd  */
    161  1.28  dholland static void
    162  1.22       jmc c_day(const char *s_day, const char *s_start, const char *s_stop)
    163   1.1       cgd {
    164  1.12   hubertf 	static const char *const days[] = {
    165   1.1       cgd 		"sunday", "monday", "tuesday", "wednesday",
    166   1.1       cgd 		"thursday", "friday", "saturday",
    167   1.1       cgd 	};
    168   1.1       cgd 	static struct tm *ct;
    169   1.1       cgd 	int start, stop;
    170   1.1       cgd 
    171   1.1       cgd 	if (!ct)
    172   1.1       cgd 		ct = localtime(&now);
    173   1.1       cgd 	if (strcasecmp(s_day, days[ct->tm_wday]))
    174   1.1       cgd 		return;
    175  1.30    rillig 	if (!isdigit((unsigned char)*s_start) ||
    176  1.22       jmc 	    !isdigit((unsigned char)*s_stop))
    177   1.1       cgd 		return;
    178   1.1       cgd 	start = atoi(s_start);
    179   1.1       cgd 	stop = atoi(s_stop);
    180  1.13       jsm 	if (ct->tm_hour >= start && ct->tm_hour < stop) {
    181  1.13       jsm 		if (start == 0 && stop == 24)
    182  1.13       jsm 			errx(0, "Sorry, games are not available today.");
    183  1.13       jsm 		else
    184  1.13       jsm 			errx(0, "Sorry, games are not available from %s to %s today.",
    185  1.13       jsm 			     hour(start), hour(stop));
    186  1.13       jsm 	}
    187   1.1       cgd }
    188   1.1       cgd 
    189   1.1       cgd /*
    190   1.1       cgd  * c_tty --
    191   1.1       cgd  *	decide if this tty can be used for games.
    192   1.1       cgd  */
    193  1.28  dholland static void
    194  1.22       jmc c_tty(const char *tty)
    195   1.1       cgd {
    196   1.1       cgd 	static int first = 1;
    197   1.1       cgd 	static char *p_tty;
    198   1.1       cgd 
    199   1.1       cgd 	if (first) {
    200   1.7     lukem 		p_tty = strrchr(gametty, '/');
    201   1.1       cgd 		first = 0;
    202   1.1       cgd 	}
    203   1.1       cgd 
    204   1.7     lukem 	if (!strcmp(gametty, tty) || (p_tty && !strcmp(p_tty, tty)))
    205   1.7     lukem 		errx(1, "Sorry, you may not play games on %s.", gametty);
    206   1.1       cgd }
    207   1.1       cgd 
    208   1.1       cgd /*
    209   1.1       cgd  * c_game --
    210   1.1       cgd  *	see if game can be played now.
    211   1.1       cgd  */
    212  1.28  dholland static void
    213  1.30    rillig c_game(const char *s_game, const char *s_load, const char *s_users,
    214  1.22       jmc        const char *s_priority)
    215   1.1       cgd {
    216   1.1       cgd 	static int found;
    217   1.1       cgd 
    218   1.1       cgd 	if (found)
    219   1.1       cgd 		return;
    220   1.1       cgd 	if (strcmp(game, s_game) && strcasecmp("default", s_game))
    221   1.1       cgd 		return;
    222   1.1       cgd 	++found;
    223  1.21       dsl 	if (isdigit((unsigned char)*s_load) && atoi(s_load) < load())
    224   1.7     lukem 		errx(0, "Sorry, the load average is too high right now.");
    225  1.21       dsl 	if (isdigit((unsigned char)*s_users) && atoi(s_users) <= users())
    226   1.7     lukem 		errx(0, "Sorry, there are too many users logged on right now.");
    227  1.21       dsl 	if (isdigit((unsigned char)*s_priority))
    228   1.1       cgd 		priority = atoi(s_priority);
    229   1.1       cgd }
    230   1.1       cgd 
    231   1.1       cgd /*
    232   1.1       cgd  * load --
    233   1.1       cgd  *	return 15 minute load average
    234   1.1       cgd  */
    235  1.28  dholland static double
    236  1.22       jmc load(void)
    237   1.1       cgd {
    238   1.1       cgd 	double avenrun[3];
    239   1.1       cgd 
    240   1.7     lukem 	if (getloadavg(avenrun, sizeof(avenrun)/sizeof(avenrun[0])) < 0)
    241  1.15       jsm 		err(1, "getloadavg() failed");
    242   1.9       mrg 	return (avenrun[2]);
    243   1.1       cgd }
    244   1.1       cgd 
    245   1.1       cgd /*
    246   1.1       cgd  * users --
    247   1.1       cgd  *	return current number of users
    248   1.1       cgd  *	todo: check idle time; if idle more than X minutes, don't
    249   1.1       cgd  *	count them.
    250   1.1       cgd  */
    251  1.28  dholland static int
    252  1.22       jmc users(void)
    253   1.1       cgd {
    254  1.17  christos 	struct utmpentry *ep;
    255  1.17  christos 	int nusers;
    256  1.17  christos 
    257  1.17  christos 	nusers = getutentries(NULL, &ep);
    258  1.17  christos 	return nusers;
    259   1.1       cgd }
    260   1.1       cgd 
    261  1.28  dholland static void
    262  1.22       jmc nogamefile(void)
    263   1.1       cgd {
    264   1.7     lukem 	int fd, n;
    265   1.1       cgd 	char buf[BUFSIZ];
    266   1.1       cgd 
    267   1.1       cgd 	if ((fd = open(_PATH_NOGAMES, O_RDONLY, 0)) >= 0) {
    268   1.1       cgd #define	MESG	"Sorry, no games right now.\n\n"
    269   1.1       cgd 		(void)write(2, MESG, sizeof(MESG) - 1);
    270   1.1       cgd 		while ((n = read(fd, buf, sizeof(buf))) > 0)
    271   1.1       cgd 			(void)write(2, buf, n);
    272   1.1       cgd 		exit(1);
    273   1.1       cgd 	}
    274   1.1       cgd }
    275   1.1       cgd 
    276   1.1       cgd /*
    277   1.1       cgd  * hour --
    278   1.1       cgd  *	print out the hour in human form
    279   1.1       cgd  */
    280  1.28  dholland static const char *
    281  1.22       jmc hour(int h)
    282   1.1       cgd {
    283  1.12   hubertf 	static const char *const hours[] = {
    284   1.7     lukem 	    "midnight", "1am", "2am", "3am", "4am", "5am",
    285   1.7     lukem 	    "6am", "7am", "8am", "9am", "10am", "11am",
    286   1.7     lukem 	    "noon", "1pm", "2pm", "3pm", "4pm", "5pm",
    287  1.13       jsm 	    "6pm", "7pm", "8pm", "9pm", "10pm", "11pm", "midnight" };
    288   1.7     lukem 
    289  1.13       jsm 	if (h < 0 || h > 24)
    290   1.9       mrg 		return ("BAD TIME");
    291   1.7     lukem 	else
    292   1.9       mrg 		return (hours[h]);
    293   1.1       cgd }
    294   1.1       cgd 
    295   1.1       cgd #ifdef LOG
    296   1.1       cgd /*
    297   1.1       cgd  * logfile --
    298   1.1       cgd  *	log play of game
    299   1.1       cgd  */
    300  1.28  dholland static void
    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.29  dholland 			sleep(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.27  dholland 		(void)flock(fileno(lp), LOCK_UN);
    325   1.1       cgd 		(void)fclose(lp);
    326   1.1       cgd 	}
    327   1.1       cgd }
    328   1.1       cgd #endif /* LOG */
    329