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