"inprogressdir" { return TYPE_PATH_INPROGRESS; }
"game_args" { return TYPE_GAME_ARGS; }
"rc_fmt" { return TYPE_RC_FMT; }
+"ttyrecdir" { return TYPE_PATH_TTYREC; }
server_id { return TYPE_SERVER_ID; }
sortmode { return TYPE_WATCH_SORTMODE; }
commands { return TYPE_CMDQUEUE; }
%token TYPE_ALLOW_REGISTRATION
%token TYPE_PATH_GAME TYPE_NAME_GAME TYPE_PATH_DGLDIR TYPE_PATH_SPOOL
%token TYPE_PATH_BANNER TYPE_PATH_CANNED TYPE_PATH_CHROOT
-%token TYPE_PATH_PASSWD TYPE_PATH_LOCKFILE
+%token TYPE_PATH_PASSWD TYPE_PATH_LOCKFILE TYPE_PATH_TTYREC
%token TYPE_MALSTRING TYPE_PATH_INPROGRESS TYPE_GAME_ARGS TYPE_RC_FMT
%token TYPE_CMDQUEUE TYPE_DEFINE_MENU TYPE_BANNER_FILE TYPE_CURSOR
%token <s> TYPE_VALUE
myconfig[ncnf]->spool = strdup($3);
break;
+ case TYPE_PATH_TTYREC:
+ if (myconfig[ncnf]->ttyrecdir) free(myconfig[ncnf]->ttyrecdir);
+ myconfig[ncnf]->ttyrecdir = strdup($3);
+ break;
+
case TYPE_PATH_GAME:
if (myconfig[ncnf]->game_path) free(myconfig[ncnf]->game_path);
myconfig[ncnf]->game_path = strdup ($3);
| TYPE_PATH_SPOOL { $$ = TYPE_PATH_SPOOL; }
| TYPE_PATH_BANNER { $$ = TYPE_PATH_BANNER; }
| TYPE_PATH_CANNED { $$ = TYPE_PATH_CANNED; }
+ | TYPE_PATH_TTYREC { $$ = TYPE_PATH_TTYREC; }
| TYPE_PATH_PASSWD { $$ = TYPE_PATH_PASSWD; }
| TYPE_PATH_LOCKFILE { $$ = TYPE_PATH_LOCKFILE; }
| TYPE_PATH_INPROGRESS { $$ = TYPE_PATH_INPROGRESS; }
case TYPE_PATH_SPOOL: return "spooldir";
case TYPE_PATH_BANNER: return "banner";
case TYPE_PATH_CANNED: return "rc_template";
+ case TYPE_PATH_TTYREC: return "ttyrecdir";
case TYPE_PATH_INPROGRESS: return "inprogressdir";
case TYPE_GAME_ARGS: return "game_args";
case TYPE_RC_FMT: return "rc_fmt";
AC_SUBST(EDITOR)
+AC_ARG_ENABLE(enable-debugfile,
+[AC_HELP_STRING([--enable-debugfile], [Enable debugging output to a file.])],
+[], [])
+
+if test "$enable_debugfile" = yes; then
+ AC_MSG_RESULT([Enabling debugging output to a file.])
+ AC_DEFINE(USE_DEBUGFILE,1,[Output debugging into to a file in chroot.])
+fi
+
+
AC_ARG_ENABLE(enable-sqlite,
[AC_HELP_STRING([--enable-sqlite], [Use SQLite for the database instead of flat text file.])],
[], [])
ttyrec_getpty ()
{
#ifdef HAVE_OPENPTY
- if (openpty (&master, &slave, NULL, NULL, NULL) == -1)
- graceful_exit (62);
+ if (openpty (&master, &slave, NULL, NULL, NULL) == -1) {
+ debug_write("cannot openpty");
+ graceful_exit (62);
+ }
#else
- if ((master = open ("/dev/ptmx", O_RDWR)) < 0)
- graceful_exit (62);
+ if ((master = open ("/dev/ptmx", O_RDWR)) < 0) {
+ debug_write("cannot open /dev/ptmx");
+ graceful_exit (62);
+ }
grantpt (master);
unlockpt (master);
if ((slave = open ((const char *) ptsname (master), O_RDWR)) < 0)
{
+ debug_write("cannot open master ptsname");
graceful_exit (65);
}
#endif
fl.l_start = 0;
fl.l_len = 0;
- len = strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir)) + strlen(me->username) + strlen(ttyrec_filename) + 13;
+ len = strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL)) + strlen(me->username) + strlen(ttyrec_filename) + 13;
lockfile = calloc(len, sizeof(char));
- snprintf (lockfile, len, "%s%s:%s", dgl_format_str(game, me, myconfig[game]->inprogressdir),
+ snprintf (lockfile, len, "%s%s:%s", dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL),
me->username, ttyrec_filename);
fd = open (lockfile, O_WRONLY | O_CREAT, 0644);
- if (fcntl (fd, F_SETLKW, &fl) == -1)
+ if (fcntl (fd, F_SETLKW, &fl) == -1) {
+ debug_write("cannot fnctl inprogress-lock");
graceful_exit (68);
+ }
write (fd, filebuf, strlen (filebuf));
kill (child, SIGHUP);
sleep (5);
}
+ debug_write("catchup sighup");
graceful_exit (2);
}
/* reuse the char* */
replacestr = strchr (ttyrecname, ':');
- if (!replacestr)
+ if (!replacestr) {
+ debug_write("inprogressmenu replacestr");
graceful_exit (145);
+ }
/*replacestr[0] = '/';*/
int error = 2;
/* A precondition is that struct `me' exists because we can be not-yet-logged-in. */
- if (!me)
+ if (!me) {
+ debug_write("no 'me' in changepw");
graceful_exit (122); /* Die. */
+ }
while (error)
{
if (*buf == '\0')
return 0;
- if (strchr (buf, ':') != NULL)
+ if (strchr (buf, ':') != NULL) {
+ debug_write("cannot have ':' in passwd");
graceful_exit (112);
+ }
mvaddstr (12, 1, "And again:");
mvaddstr (13, 1, "=> ");
if (strlen(from) < 1) {
fprintf(stderr, "Error: wall: 'from' username is too short!\n");
+ debug_write("wall: 'from' username too short");
graceful_exit(121);
}
if (strlen(msg) >= 80) {
fprintf(stderr, "Error: wall: message too long!\n");
+ debug_write("wall: message too long");
graceful_exit(120);
}
if (len == 0) {
fprintf(stderr, "Error: wall: no one's logged in!\n");
+ debug_write("wall: no people playing");
graceful_exit(118);
}
if (!nolock)
{
fpl = fopen (globalconfig.lockfile, "r");
- if (!fpl)
+ if (!fpl) {
+ debug_write("cannot fopen lockfile");
graceful_exit (106);
- if (fcntl (fileno (fpl), F_SETLKW, &fl) == -1)
+ }
+ if (fcntl (fileno (fpl), F_SETLKW, &fl) == -1) {
+ debug_write("cannot fcntl lockfile");
graceful_exit (114);
+ }
}
fp = fopen (globalconfig.passwd, "r");
- if (!fp)
+ if (!fp) {
+ debug_write("cannot fopen passwd file");
graceful_exit (106);
+ }
/* once per name in the file */
while (fgets (buf, 1200, fp))
return 1;
users[f_num]->username[(b - n)] = *b;
b++;
- if ((b - n) >= 21)
+ if ((b - n) >= 21) {
+ debug_write("name field too long");
graceful_exit (100);
+ }
}
/* advance to next field */
{
users[f_num]->email[(b - n)] = *b;
b++;
- if ((b - n) > 80)
+ if ((b - n) > 80) {
+ debug_write("email field too long");
graceful_exit (101);
+ }
}
/* advance to next field */
{
users[f_num]->password[(b - n)] = *b;
b++;
- if ((b - n) >= 20)
+ if ((b - n) >= 20) {
+ debug_write("passwd field too long");
graceful_exit (102);
+ }
}
/* advance to next field */
{
users[f_num]->env[(b - n)] = *b;
b++;
- if ((b - n) >= 1024)
+ if ((b - n) >= 1024) {
+ debug_write("env field too long");
graceful_exit (102);
+ }
}
f_num++;
if (f_num > globalconfig.max)
{
fprintf(stderr,"ERROR: number of users in database exceeds maximum. Exiting.\n");
+ debug_write("too many users in database");
graceful_exit (109);
}
}
ret = sqlite3_open(USE_SQLITE_DB, &db); /* FIXME: use globalconfig->passwd? */
if (ret) {
sqlite3_close(db);
+ debug_write("sqlite3_open failed");
graceful_exit(109);
}
if (ret != SQLITE_OK) {
sqlite3_close(db);
+ debug_write("sqlite3_exec failed");
graceful_exit(108);
}
sqlite3_close(db);
char *myargv[3];
pid_t editor;
- rcfile = fopen (dgl_format_str(game, me, myconfig[game]->rc_fmt), "r");
+ rcfile = fopen (dgl_format_str(game, me, myconfig[game]->rc_fmt, NULL), "r");
if (!rcfile)
- write_canned_rcfile (game, dgl_format_str(game, me, myconfig[game]->rc_fmt));
+ write_canned_rcfile (game, dgl_format_str(game, me, myconfig[game]->rc_fmt, NULL));
/* use whatever editor_main to edit */
myargv[0] = "";
- myargv[1] = dgl_format_str(game, me, myconfig[game]->rc_fmt);
+ myargv[1] = dgl_format_str(game, me, myconfig[game]->rc_fmt, NULL);
myargv[2] = 0;
endwin ();
if (editor == -1)
{
perror("fork");
+ debug_write("edit fork failed");
graceful_exit(114);
}
else if (editor == 0)
if (!fpl)
{
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ debug_write("writefile locking failed");
graceful_exit (115);
}
if (fcntl (fileno (fpl), F_SETLK, &fl))
{
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ debug_write("writefile fcntl failed");
graceful_exit (107);
}
if (!fp)
{
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ debug_write("passwd file fopen failed");
graceful_exit (104);
}
fclose(fp);
fclose(fpl);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ debug_write("two users registering at the same time");
graceful_exit (111);
}
fprintf (fp, "%s:%s:%s:%s\n", me->username, me->email, me->password,
fclose(fp);
fclose(fpl);
sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ debug_write("too many users in passwd db already");
graceful_exit (116);
}
}
ret = sqlite3_open(USE_SQLITE_DB, &db); /* FIXME: use globalconfig->passwd? */
if (ret) {
sqlite3_close(db);
+ debug_write("writefile sqlite3_open failed");
graceful_exit(107);
}
if (ret != SQLITE_OK) {
sqlite3_close(db);
+ debug_write("writefile sqlite3_exec failed");
graceful_exit(106);
}
sqlite3_close(db);
size_t len;
short firsttime = 1;
- dir = strdup(dgl_format_str(game, me, myconfig[game]->inprogressdir));
+ dir = strdup(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL));
- if (!(pdir = opendir (dir)))
+ if (!(pdir = opendir (dir))) {
+ debug_write("purge_stale_locks dir open failed");
graceful_exit (200);
+ }
free(dir);
colon = strchr (dent->d_name, ':');
/* should never happen */
- if (!colon)
+ if (!colon) {
+ debug_write("purge_stale_locks !colon");
graceful_exit (201);
-
+ }
if (colon - dent->d_name != strlen(me->username))
continue;
if (strncmp (dent->d_name, me->username, colon - dent->d_name))
continue;
- len = strlen (dent->d_name) + strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir)) + 1;
+ len = strlen (dent->d_name) + strlen(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL)) + 1;
fn = malloc (len);
- snprintf (fn, len, "%s%s", dgl_format_str(game, me, myconfig[game]->inprogressdir), dent->d_name);
+ snprintf (fn, len, "%s%s", dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL), dent->d_name);
- if (!(ipfile = fopen (fn, "r")))
+ if (!(ipfile = fopen (fn, "r"))) {
+ debug_write("purge_stale_locks fopen inprogressdir fail");
graceful_exit (202);
+ }
- if (fgets (buf, 16, ipfile) == NULL)
+ if (fgets (buf, 16, ipfile) == NULL) {
+ debug_write("purge_stale_locks fgets ipfile fail");
graceful_exit (203);
+ }
fclose (ipfile);
endwin ();
fprintf (stderr, "Sorry, no %s for you now, please "
"contact the admin.\n", myconfig[game]->game_name);
+ debug_write("could not terminate stale processes");
graceful_exit (1);
}
}
}
if (check_retard(0)) {
+ debug_write("retard");
graceful_exit(119);
}
}
if (wall_email_str) {
char *emailfrom = wall_email_str;
char *emailmsg = strchr(wall_email_str, ':');
- if (!emailmsg)
+ if (!emailmsg) {
+ debug_write("wall: no mail msg");
graceful_exit(117);
+ }
*emailmsg = '\0';
emailmsg++;
if (emailmsg)
}
/* simple login routine, uses ncurses */
- if (readfile (0))
+ if (readfile (0)) {
+ debug_write("log in fail");
graceful_exit (110);
+ }
- if (nhauth)
+ if (nhauth) {
+ debug_write("nhauth");
graceful_exit (authenticate ());
+ }
if (auth)
{
char* game_name;
char* shortname;
char* rcfile;
+ char* ttyrecdir;
char* spool;
char* inprogressdir;
int num_args; /* # of bin_args */
extern void loadbanner(char *fname, struct dg_banner *ban);
extern void drawbanner(struct dg_banner *ban, unsigned int start_line, unsigned int howmany);
extern int check_retard(int reset);
-extern char *dgl_format_str(int game, struct dg_user *me, char *str);
+extern char *dgl_format_str(int game, struct dg_user *me, char *str, char *plrname);
extern struct dg_menu *dgl_find_menu(char *menuname);
extern struct dg_game **populate_games(int game, int *l, struct dg_user *me);
+#ifdef USE_DEBUGFILE
+extern void debug_write(char *str);
+#else
+#define debug_write(str)
+#endif
+
extern struct dg_game **sort_games(struct dg_game **games, int len, dg_sortmode sortmode);
int runmenuloop(struct dg_menu *menu);
/* max = */ /*64000,*/
/* savefilefmt = */ /*"",*/ /* don't do this by default */
/* inprogressdir = */ "%rinprogress/",
+ NULL,
/* num_args = */ 0,
/* bin_args = */ NULL,
/* rc_fmt = */ "%rrcfiles/%n.nethackrc", /* [dglroot]rcfiles/[username].nethackrc */
/*
* replace following codes with variables:
* %u == shed_uid (number)
- * %n == user name (string)
+ * %n == user name (string; gotten from 'me', or from 'plrname' if 'me' is null)
* %r == chroot (string) (aka "dglroot" config var)
* %g == game name
*/
char *
-dgl_format_str(int game, struct dg_user *me, char *str)
+dgl_format_str(int game, struct dg_user *me, char *str, char *plrname)
{
static char buf[1024];
char *f, *p, *end;
break;
case 'n':
if (me) snprintf (p, end + 1 - p, "%s", me->username);
+ else if (plrname) snprintf(p, end + 1 - p, "%s", plrname);
+ else return NULL;
while (*p != '\0')
p++;
break;
case 'g':
if (game >= 0 && game < num_games && myconfig[game]) snprintf (p, end + 1 - p, "%s", myconfig[game]->game_name);
+ else return NULL;
while (*p != '\0')
p++;
break;
return_from_submenu = 0;
while (tmp && !return_from_submenu) {
- if (tmp->param1) strcpy(p1, dgl_format_str(game, me, tmp->param1));
- if (tmp->param2) strcpy(p2, dgl_format_str(game, me, tmp->param2));
+ if (tmp->param1) strcpy(p1, dgl_format_str(game, me, tmp->param1, NULL));
+ if (tmp->param2) strcpy(p2, dgl_format_str(game, me, tmp->param2, NULL));
switch (tmp->cmd) {
default: break;
child = fork();
if (child == -1) {
perror("fork");
+ debug_write("exec-command fork failed");
graceful_exit(114);
} else if (child == 0) {
execvp(p1, myargv);
if (!loggedin && globalconfig.allow_registration) newuser();
break;
case DGLCMD_QUIT:
+ debug_write("command: quit");
graceful_exit(0);
/* break; */
case DGLCMD_SUBMENU:
if (!strcmp(myconfig[userchoice]->game_name, p1) || !strcmp(myconfig[userchoice]->shortname, p1)) {
if (purge_stale_locks(userchoice)) {
if (myconfig[userchoice]->rcfile) {
- if (access (dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt), R_OK) == -1)
- write_canned_rcfile (userchoice, dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt));
+ if (access (dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL), R_OK) == -1)
+ write_canned_rcfile (userchoice, dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt, NULL));
}
setproctitle("%s [playing %s]", me->username, myconfig[userchoice]->shortname);
/* fix the variables in the arguments */
for (i = 0; i < myconfig[userchoice]->num_args; i++) {
- tmpstr = strdup(dgl_format_str(userchoice, me, myconfig[userchoice]->bin_args[i]));
+ tmpstr = strdup(dgl_format_str(userchoice, me, myconfig[userchoice]->bin_args[i], NULL));
free(myconfig[userchoice]->bin_args[i]);
myconfig[userchoice]->bin_args[i] = tmpstr;
}
/* launch program */
- ttyrec_main (userchoice, me->username, dgl_format_str(userchoice, me, "%ruserdata/%n/ttyrec"), gen_ttyrec_filename());
+ ttyrec_main (userchoice, me->username,
+ dgl_format_str(userchoice, me, myconfig[userchoice]->ttyrecdir, NULL),
+ gen_ttyrec_filename());
/* lastly, run the generic "do these when a game is left" commands */
dgl_exec_cmdqueue(globalconfig.cmdqueue[DGLTIME_GAMEEND], userchoice, me);
return games;
}
+#ifdef USE_DEBUGFILE
+void
+debug_write(char *str)
+{
+ FILE *fp;
+ fp = fopen("/dgldebug.log", "a");
+ if (!fp) return;
+ fprintf(fp, "%s\n", str);
+ fclose(fp);
+
+}
+#endif /* USE_DEBUGFILE */
+
struct dg_game **
populate_games (int xgame, int *l, struct dg_user *me)
{
for (game = ((xgame < 0) ? 0 : xgame); game < ((xgame <= 0) ? num_games : (xgame+1)); game++) {
- dir = strdup(dgl_format_str(game, me, myconfig[game]->inprogressdir));
+ dir = strdup(dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL));
+ if (!dir) continue;
- if (!(pdir = opendir (dir)))
- graceful_exit (140);
+ if (!(pdir = opendir (dir))) {
+ debug_write("cannot open inprogress-dir");
+ graceful_exit (140);
+ }
while ((pdirent = readdir (pdir)))
{
+ char *inprog = NULL;
if (!strcmp (pdirent->d_name, ".") || !strcmp (pdirent->d_name, ".."))
continue;
is_nhext = !strcmp (pdirent->d_name + strlen (pdirent->d_name) - 6, ".nhext");
- snprintf (fullname, 130, "%s%s", dgl_format_str(game, me, myconfig[game]->inprogressdir), pdirent->d_name);
+ inprog = dgl_format_str(game, me, myconfig[game]->inprogressdir, NULL);
+
+ if (!inprog) continue;
+
+ snprintf (fullname, 130, "%s%s", inprog, pdirent->d_name);
fd = 0;
/* O_RDWR here should be O_RDONLY, but we need to test for
/* stat to check idle status */
if (!is_nhext)
{
+ char *ttrecdir = NULL;
strncpy(playername, pdirent->d_name, 29);
playername[29] = '\0';
if ((replacestr = strchr(playername, ':')))
*replacestr = '\0';
replacestr = strchr(pdirent->d_name, ':');
- if (!replacestr) graceful_exit(145);
+ if (!replacestr) {
+ debug_write("inprogress-filename does not have ':'");
+ graceful_exit(145);
+ }
replacestr++;
- snprintf (ttyrecname, 130, "%suserdata/%s/ttyrec/%s", globalconfig.dglroot, playername, replacestr);
+
+ ttrecdir = dgl_format_str(game, me, myconfig[game]->ttyrecdir, playername);
+ if (!ttrecdir) continue;
+ snprintf (ttyrecname, 130, "%s%s", ttrecdir, replacestr);
}
if (is_nhext || !stat (ttyrecname, &pstat))
{
games[len] = malloc (sizeof (struct dg_game));
games[len]->ttyrec_fn = strdup (ttyrecname);
- if (!(replacestr = strchr (pdirent->d_name, ':')))
- graceful_exit (146);
- else
+ if (!(replacestr = strchr (pdirent->d_name, ':'))) {
+ debug_write("inprogress-filename does not have ':', pt. 2");
+ graceful_exit (146);
+ } else
*replacestr = '\0';
games[len]->name = malloc (strlen (pdirent->d_name) + 1);
else
{
fprintf(stderr, "ERROR: can't find or open %s for reading\n", config);
+ debug_write("cannot read config file");
graceful_exit(104);
return;
}
fclose(config_file);
} else {
fprintf(stderr, "ERROR: can't find or open %s for reading\n", config);
- graceful_exit(104);
+ debug_write("cannot read default config file");
+ graceful_exit(105);
return;
}
#else
if (!myconfig) /* a parse error occurred */
{
fprintf(stderr, "ERROR: configuration parsing failed\n");
+ debug_write("config file parsing failed");
graceful_exit(113);
}
inprogressdir = "%rinprogress-nh343/"
+# The place where ttyrecs are stored for this game.
+# If this is not defined, ttyrecs are not saved for this game.
+# Leaving this undefined also means the games cannot be spectated.
+ ttyrecdir = "%ruserdata/%n/ttyrec/"
+
# back up savefile
commands = cp "/nh343/var/save/%u%n.gz" "/nh343/var/save/%u%n.gz.bak",
child = subchild = input_child = 0;
+ if (!ttyrec_path) {
+ child = fork();
+ if (child < 0) {
+ perror ("fork");
+ fail ();
+ }
+ if (child == 0) {
+ execvp (myconfig[game]->game_path, myconfig[game]->bin_args);
+ } else {
+ int status;
+ (void) wait(&status);
+ }
+ return 0;
+ }
+
if (ttyrec_path[strlen(ttyrec_path)-1] == '/')
snprintf (dirname, 100, "%s%s", ttyrec_path, ttyrec_filename);
else