dgamelaunch/ttyrec.c

379 lines
7.8 KiB
C

/*
* Copyright (c) 1980 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
* - added Native Language Support
*/
/* 2000-12-27 Satoru Takabayashi <satoru@namazu.org>
* - modify `script' to create `ttyrec'.
*/
/*
* script
*/
#include "dgamelaunch.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <termios.h>
#include <time.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#ifndef NOSTREAMS
# include <stropts.h>
#endif
#include <stdlib.h>
#include "ttyrec.h"
#include "io.h"
#ifndef XCASE
# define XCASE 0
#endif
int slave;
pid_t child, subchild;
char* ipfile = NULL;
FILE *fscript;
int master;
struct termios tt;
struct winsize win;
int uflg;
int
ttyrec_main (char *username, char* ttyrec_filename)
{
char dirname[100];
snprintf (dirname, 100, "%sttyrec/%s/%s", myconfig->dglroot, username,
ttyrec_filename);
atexit(&remove_ipfile);
if ((fscript = fopen (dirname, "w")) == NULL)
{
perror (dirname);
fail ();
}
setbuf (fscript, NULL);
fixtty ();
(void) signal (SIGCHLD, finish);
child = fork ();
if (child < 0)
{
perror ("fork");
fail ();
}
if (child == 0)
{
subchild = child = fork ();
if (child < 0)
{
perror ("fork");
fail ();
}
if (child)
{
close (slave);
ipfile = gen_inprogress_lock (child, ttyrec_filename);
dooutput ();
}
else
doshell (username);
}
doinput ();
unlink (ipfile);
return 0;
}
void
doinput ()
{
register int cc;
char ibuf[BUFSIZ];
(void) fclose (fscript);
while ((cc = read (0, ibuf, BUFSIZ)) > 0)
(void) write (master, ibuf, cc);
done ();
}
void
finish (int sig)
{
int status;
register int pid;
register int die = 0;
(void)sig; /* unused */
while ((pid = wait3 (&status, WNOHANG, 0)) > 0)
{
if (pid == child)
die = 1;
}
if (die)
done ();
}
struct linebuf
{
char str[BUFSIZ + 1]; /* + 1 for an additional NULL character. */
int len;
};
void
check_line (const char *line)
{
static int uuencode_mode = 0;
static FILE *uudecode;
if (uuencode_mode == 1)
{
fprintf (uudecode, "%s", line);
if (strcmp (line, "end\n") == 0)
{
pclose (uudecode);
uuencode_mode = 0;
}
}
else
{
int dummy;
char dummy2[BUFSIZ];
if (sscanf (line, "begin %o %s", &dummy, dummy2) == 2)
{
/*
* uuencode line found!
*/
uudecode = popen ("uudecode", "w");
fprintf (uudecode, "%s", line);
uuencode_mode = 1;
}
}
}
void
check_output (const char *str, int len)
{
static struct linebuf lbuf = { "", 0 };
int i;
for (i = 0; i < len; i++)
{
if (lbuf.len < BUFSIZ)
{
lbuf.str[lbuf.len] = str[i];
if (lbuf.str[lbuf.len] == '\r')
{
lbuf.str[lbuf.len] = '\n';
}
lbuf.len++;
if (lbuf.str[lbuf.len - 1] == '\n')
{
if (lbuf.len > 1)
{ /* skip a blank line. */
lbuf.str[lbuf.len] = '\0';
check_line (lbuf.str);
}
lbuf.len = 0;
}
}
else
{ /* buffer overflow */
lbuf.len = 0;
}
}
}
void
dooutput ()
{
int cc;
time_t tvec, time ();
char obuf[BUFSIZ], *ctime ();
setbuf (stdout, NULL);
(void) close (0);
tvec = time ((time_t *) NULL);
for (;;)
{
Header h;
cc = read (master, obuf, BUFSIZ);
if (cc <= 0)
break;
if (uflg)
check_output (obuf, cc);
h.len = cc;
gettimeofday (&h.tv, NULL);
(void) write (1, obuf, cc);
(void) write_header (fscript, &h);
(void) fwrite (obuf, 1, cc, fscript);
}
done ();
}
void
doshell (char *username)
{
char *argv1 = myconfig->nethack;
char *argv2 = "-u";
char *myargv[10];
getslave ();
(void) close (master);
(void) fclose (fscript);
(void) dup2 (slave, 0);
(void) dup2 (slave, 1);
(void) dup2 (slave, 2);
(void) close (slave);
myargv[0] = argv1;
myargv[1] = argv2;
myargv[2] = username;
myargv[3] = 0;
execvp (myconfig->nethack, myargv);
fail ();
}
void
fixtty ()
{
struct termios rtt;
rtt = tt;
rtt.c_iflag = 0;
rtt.c_lflag &= ~(ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK | ECHONL);
rtt.c_oflag = OPOST;
rtt.c_cc[VINTR] = _POSIX_VDISABLE;
rtt.c_cc[VQUIT] = _POSIX_VDISABLE;
rtt.c_cc[VERASE] = _POSIX_VDISABLE;
rtt.c_cc[VKILL] = _POSIX_VDISABLE;
rtt.c_cc[VEOF] = 1;
rtt.c_cc[VEOL] = 0;
rtt.c_cc[VMIN] = 1;
rtt.c_cc[VTIME] = 0;
(void) tcsetattr (0, TCSAFLUSH, &rtt);
}
void
fail ()
{
(void) kill (0, SIGTERM);
done ();
}
void
done ()
{
time_t tvec, time ();
char *ctime ();
if (subchild)
{
tvec = time ((time_t *) NULL);
(void) fclose (fscript);
(void) close (master);
}
else
{
(void) tcsetattr (0, TCSAFLUSH, &tt);
}
unlink(ipfile);
graceful_exit (0);
}
void
getslave ()
{
(void) setsid ();
/* grantpt( master);
unlockpt(master);
if ((slave = open((const char *)ptsname(master), O_RDWR)) < 0) {
perror((const char *)ptsname(master));
fail();
perror("open(fd, O_RDWR)");
fail();
} */
#ifndef NOSTREAMS
if (isastream (slave))
{
if (ioctl (slave, I_PUSH, "ptem") < 0)
{
perror ("ioctl(fd, I_PUSH, ptem)");
fail ();
}
if (ioctl (slave, I_PUSH, "ldterm") < 0)
{
perror ("ioctl(fd, I_PUSH, ldterm)");
fail ();
}
#ifndef _HPUX_SOURCE
if (ioctl (slave, I_PUSH, "ttcompat") < 0)
{
perror ("ioctl(fd, I_PUSH, ttcompat)");
fail ();
}
#endif
}
#endif /* !NOSTREAMS */
(void) ioctl (0, TIOCGWINSZ, (char *) &win);
}
void
remove_ipfile (void)
{
if (ipfile != NULL)
unlink (ipfile);
}