CFLAGS = -g3 $(optimize) -Wall -Wno-unused $(DEFS)
INSTALL = install -c
DEFS = -DVERSION=\"$(VERSION)\" -DDEFCONFIG=\"$(DEFCONFIG)\"
-SRCS = $(EDITOR) ttyrec.c dgamelaunch.c io.c ttyplay.c mygetnstr.c stripgfx.c strlcpy.c strlcat.c y.tab.c lex.yy.c
+SRCS = $(EDITOR) dgl-common.c ttyrec.c dgamelaunch.c io.c ttyplay.c mygetnstr.c stripgfx.c strlcpy.c strlcat.c y.tab.c lex.yy.c
+EXTRA_SRCS = nethackstub.c
OBJS = $(SRCS:.c=.o)
+WALL_OBJS = y.tab.o lex.yy.o dgl-common.o dgl-wall.o strlcat.o strlcpy.o
LIBS = -lcurses -lcrypt $(LUTIL) -ll
-all: $(NAME)
+all: $(NAME) dgl-wall
$(NAME): $(OBJS)
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS)
+dgl-wall: $(WALL_OBJS)
+ $(CC) $(CFLAGS) -o $@ $(WALL_OBJS) $(LIBS)
+
clean:
- rm -f $(NAME) nethackstub
- rm -f editors/*.o *.o .#* *~ y.tab.* lex.yy.c
+ rm -f $(NAME) nethackstub dgl-wall
+ rm -f editors/*.o *.o .#* *~ y.tab.* lex.yy.c Makefile.dep
install:
$(INSTALL) -m 755 $(NAME) $(SBINDIR)
lex.yy.o: lex.yy.c
y.tab.o: y.tab.c
-dist: clean
+dist: dep clean
rm -rf $(NAME)-$(VERSION)
(cd .. && ln -sf $(CURDIR) $(NAME)-$(VERSION))
(cd .. && tar $(addprefix --exclude ,$(exclusions)) -chzf $(NAME)-$(VERSION).tar.gz $(NAME)-$(VERSION))
rm -f ../$(NAME)-$(VERSION)
@echo "Created source release $(NAME)-$(VERSION).tar.gz"
-
-# Dependencies - we may auto-generate later
+
+dep: y.tab.c lex.yy.c
+ @sed -e '/^# Source code dependencies/,$$d' < Makefile > Makefile.dep
+ @echo "# Source code dependencies" >> Makefile.dep
+ $(CC) -MM $(SRCS) $(EXTRA_SRCS) >> Makefile.dep
+ mv Makefile.dep Makefile
+
+# Source code dependencies
ee.o: ee.c
+dgl-common.o: dgl-common.c dgamelaunch.h
+ttyrec.o: ttyrec.c dgamelaunch.h ttyrec.h io.h
+dgamelaunch.o: dgamelaunch.c dgamelaunch.h ttyplay.h ttyrec.h y.tab.h
io.o: io.c ttyrec.h
-last_char_is.o: last_char_is.c
+ttyplay.o: ttyplay.c dgamelaunch.h ttyplay.h ttyrec.h io.h stripgfx.h
mygetnstr.o: mygetnstr.c
-nethackstub.o: nethackstub.c
stripgfx.o: stripgfx.c stripgfx.h
-strlcat.o: strlcat.c
strlcpy.o: strlcpy.c
-ttyplay.o: ttyplay.c dgamelaunch.h ttyplay.h ttyrec.h io.h stripgfx.h
-ttyrec.o: ttyrec.c dgamelaunch.h ttyrec.h io.h
-virus.o: virus.c last_char_is.c
+strlcat.o: strlcat.c
y.tab.o: y.tab.c dgamelaunch.h
-dgamelaunch.o: dgamelaunch.c dgamelaunch.h ttyplay.h ttyrec.h y.tab.h
+lex.yy.o: lex.yy.c y.tab.h dgamelaunch.h
+nethackstub.o: nethackstub.c
--- /dev/null
+/* Functions common to both dgamelaunch itself and dgl-wall. */
+
+#include "dgamelaunch.h"
+#include <sys/stat.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
+
+extern FILE* yyin;
+extern int yyparse ();
+
+/* Data structures */
+struct dg_config *myconfig = NULL;
+struct dg_config defconfig = {
+ /* chroot = */ "/var/lib/dgamelaunch/",
+ /* nethack = */ "/bin/nethack",
+ /* dglroot = */ "/dgldir/",
+ /* lockfile = */ "/dgl-lock",
+ /* passwd = */ "/dgl-login",
+ /* banner = */ "/dgl-banner",
+ /* rcfile = */ "/dgl-default-rcfile",
+ /* spool = */ "/var/mail/",
+ /* shed_user = */ "games",
+ /* shed_group = */ "games",
+ /* shed_uid = */ 5,
+ /* shed_gid = */ 60, /* games:games in Debian */
+ /* max = */ 64000
+};
+
+char* config = NULL;
+int silent = 0;
+int set_max = 0; /* XXX */
+int loggedin = 0;
+char *chosen_name;
+
+struct dg_game **
+populate_games (int *l)
+{
+ int fd, len;
+ DIR *pdir;
+ struct dirent *pdirent;
+ struct stat pstat;
+ char fullname[130], ttyrecname[130];
+ char *replacestr, *dir;
+ struct dg_game **games = NULL;
+ struct flock fl = { 0 };
+ size_t slen;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ len = 0;
+
+ slen = strlen(myconfig->dglroot) + ARRAY_SIZE("inprogress/") + 1;
+ dir = malloc(slen);
+ snprintf(dir, slen, "%sinprogress/", myconfig->dglroot);
+
+ if (!(pdir = opendir (dir)))
+ graceful_exit (140);
+
+ while ((pdirent = readdir (pdir)))
+ {
+ if (!strcmp (pdirent->d_name, ".") || !strcmp (pdirent->d_name, ".."))
+ continue;
+
+ snprintf (fullname, 130, "%sinprogress/%s", myconfig->dglroot, pdirent->d_name);
+
+ fd = 0;
+ /* O_RDWR here should be O_RDONLY, but we need to test for
+ * an exclusive lock */
+ fd = open (fullname, O_RDWR);
+ if ((fd > 0) && fcntl (fd, F_SETLK, &fl) == -1)
+ {
+
+ /* stat to check idle status */
+ snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name);
+ replacestr = strchr (ttyrecname, ':');
+ if (!replacestr)
+ graceful_exit (145);
+ replacestr[0] = '/';
+ if (!stat (ttyrecname, &pstat))
+ {
+ /* now it's a valid game for sure */
+ games = realloc (games, sizeof (struct dg_game) * (len + 1));
+ games[len] = malloc (sizeof (struct dg_game));
+ games[len]->ttyrec_fn = strdup (pdirent->d_name);
+
+ if (!(replacestr = strchr (pdirent->d_name, ':')))
+ graceful_exit (146);
+ else
+ *replacestr = '\0';
+
+ games[len]->name = malloc (strlen (pdirent->d_name) + 1);
+ strlcpy (games[len]->name, pdirent->d_name,
+ strlen (pdirent->d_name) + 1);
+
+ games[len]->date = malloc (11);
+ strlcpy (games[len]->date, replacestr + 1, 11);
+
+ games[len]->time = malloc (9);
+ strlcpy (games[len]->time, replacestr + 12, 9);
+
+ games[len]->idle_time = pstat.st_mtime;
+
+ len++;
+ }
+ }
+ else
+ {
+ /* clean dead ones */
+ unlink (fullname);
+ }
+ fl.l_type = F_UNLCK;
+
+ fcntl (fd, F_SETLK, &fl);
+
+ fl.l_type = F_WRLCK;
+
+ close (fd);
+ }
+
+ closedir (pdir);
+ *l = len;
+ return games;
+}
+
+void
+create_config ()
+{
+ FILE *config_file = NULL;
+
+ if (config)
+ {
+ if ((config_file = fopen(config, "r")) != NULL)
+ {
+ yyin = config_file;
+ yyparse();
+ fclose(config_file);
+ free (config);
+ }
+ else
+ {
+ fprintf(stderr, "ERROR: can't find or open %s for reading\n", config);
+ graceful_exit(104);
+ return;
+ }
+
+ if (!myconfig) /* a parse error occurred */
+ {
+ myconfig = &defconfig;
+ return;
+ }
+ /* Fill the rest with defaults */
+ if (!myconfig->shed_user && myconfig->shed_uid == -1)
+ {
+ struct passwd *pw;
+ if ((pw = getpwnam(defconfig.shed_user)))
+ myconfig->shed_uid = pw->pw_uid;
+ else
+ myconfig->shed_uid = defconfig.shed_uid;
+ }
+
+ if (!myconfig->shed_group && myconfig->shed_gid == -1)
+ {
+ struct group *gr;
+ if ((gr = getgrnam(defconfig.shed_group)))
+ myconfig->shed_gid = gr->gr_gid;
+ else
+ myconfig->shed_gid = defconfig.shed_gid;
+ }
+
+ if (myconfig->max == 0 && !set_max) myconfig->max = defconfig.max;
+ if (!myconfig->banner) myconfig->banner = defconfig.banner;
+ if (!myconfig->chroot) myconfig->chroot = defconfig.chroot;
+ if (!myconfig->nethack) myconfig->nethack = defconfig.nethack;
+ if (!myconfig->dglroot) myconfig->dglroot = defconfig.dglroot;
+ if (!myconfig->rcfile) myconfig->rcfile = defconfig.rcfile;
+ if (!myconfig->spool) myconfig->spool = defconfig.spool;
+ if (!myconfig->passwd) myconfig->passwd = defconfig.passwd;
+ if (!myconfig->lockfile) myconfig->lockfile = defconfig.lockfile;
+ }
+ else
+ {
+ myconfig = &defconfig;
+ }
+}
+
+#if !defined(BSD) && !defined(__linux__)
+int
+mysetenv (const char* name, const char* value, int overwrite)
+{
+ int retval;
+ char *buf = NULL;
+
+ if (getenv(name) == NULL || overwrite)
+ {
+ size_t len = strlen(name) + 1 + strlen(value) + 1; /* NAME=VALUE\0 */
+ buf = malloc(len);
+ snprintf(buf, len, "%s=%s", name, value);
+ retval = putenv(buf);
+ }
+ else
+ retval = -1;
+
+ return retval;
+}
+#endif
+
+void
+graceful_exit (int status)
+{
+ /*FILE *fp;
+ if (status != 1)
+ {
+ fp = fopen ("/crash.log", "a");
+ char buf[100];
+ sprintf (buf, "graceful_exit called with status %d", status);
+ fputs (buf, fp);
+ }
+ This doesn't work. Ever.
+ */
+ exit (status);
+}
--- /dev/null
+/* dgl-wall sends a message to all logged in users. If you specified a
+ * configuration file to dgamelaunch, you must do so as well for dgl-wall,
+ * or else the message won't be sent. */
+
+#include <fcntl.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <string.h>
+#include "dgamelaunch.h"
+
+int
+main (int argc, char** argv)
+{
+ int c, i, len;
+ char* config = NULL, buf[80], *ptr = buf, *from = NULL;
+ struct dg_game ** games = NULL;
+ struct flock fl = { 0 };
+ struct passwd* pw = getpwuid(getuid());
+ FILE* spool = NULL;
+
+ fl.l_type = F_WRLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+
+ *ptr = '\0';
+
+ while ((c = getopt(argc, argv, "f:F:")) != -1)
+ {
+ switch (c)
+ {
+ case 'f':
+ config = strdup(optarg);
+ break;
+ case 'F':
+ from = strdup(optarg);
+ break;
+ }
+ }
+
+ if (from == NULL)
+ from = pw->pw_name;
+
+ while (optind < argc)
+ {
+ if (strlen(buf) >= 80)
+ {
+ fprintf(stderr, "Error: Message is too long! (80 chars max)\n");
+ return 1;
+ }
+ else if (strlen(buf) != 0)
+ strlcat (buf, " ", 80);
+ strlcat (buf, argv[optind++], 80);
+ }
+
+ if (strlen(buf) == 0)
+ {
+ fprintf(stderr, "Error: no message?\n");
+ return 1;
+ }
+
+ create_config();
+
+ if (chroot (myconfig->chroot))
+ {
+ perror("Couldn't change root directory");
+ return 1;
+ }
+
+ if (chdir ("/"))
+ {
+ perror("Couldn't chdir to root directory");
+ return 1;
+ }
+
+ games = populate_games (&len);
+
+ if (len == 0)
+ {
+ fprintf(stderr, "Error: no one's logged in!\n");
+ return 1;
+ }
+
+ for (i = 0; i < len; i++)
+ {
+ char* fname = NULL;
+ size_t len;
+
+ len = strlen(myconfig->spool) + strlen(games[i]->name) + 2;
+ fname = malloc (len + 1);
+
+ snprintf(fname, len, "%s/%s", myconfig->spool, games[i]->name);
+
+ if ((spool = fopen(fname, "a")) == NULL)
+ {
+ fprintf (stderr, "Warning: couldn't open mailbox for %s.\n", games[i]->name);
+ free (fname);
+ continue;
+ }
+
+ while (fcntl (fileno(spool), F_SETLK, &fl) == -1)
+ {
+ if (errno != EAGAIN)
+ fprintf (stderr, "Warning: fcntl errored out trying to lock mailbox for %s\n",
+ games[i]->name);
+ sleep(1);
+ }
+
+ /* Now that we have the lock, begin the write */
+
+ fprintf(spool, "%s:%s\n", from, buf);
+ fclose(spool);
+ free(fname);
+ }
+
+ puts("Message sent successfully.");
+ return 0;
+}
+