/* xterm.c -- Definition of functions and structures for
|
/* xterm.c -- Definition of functions and structures for
|
peripheral to communicate with host through an xterm.
|
peripheral to communicate with host through an xterm.
|
Inspired from SWI-Prolog by Jan Wielemaker (GPL too)
|
Inspired from SWI-Prolog by Jan Wielemaker (GPL too)
|
even if there is really few in common.
|
even if there is really few in common.
|
|
|
Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
|
Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
|
|
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
This file is part of OpenRISC 1000 Architectural Simulator.
|
|
|
This program is free software; you can redistribute it and/or modify
|
This program is free software; you can redistribute it and/or modify
|
it under the terms of the GNU General Public License as published by
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
|
|
/*
|
/*
|
* I really dislike using stuff beginning with '_'
|
* I really dislike using stuff beginning with '_'
|
* They are suppose to be reserved for the compiler
|
* They are suppose to be reserved for the compiler
|
* as explained in C standards.
|
* as explained in C standards.
|
*/
|
*/
|
#if HAVE_CONFIG_H
|
#if HAVE_CONFIG_H
|
#include <config.h>
|
#include <config.h>
|
#endif
|
#endif
|
|
|
#define _XOPEN_SOURCE /* grantpt() and al. */
|
#define _XOPEN_SOURCE /* grantpt() and al. */
|
#define _GNU_SOURCE /* on_exit */
|
#define _GNU_SOURCE /* on_exit */
|
|
|
#include <sys/types.h> /* waitpid() */
|
#include <sys/types.h> /* waitpid() */
|
#include <sys/wait.h> /* waitpid() */
|
#include <sys/wait.h> /* waitpid() */
|
#include <stdio.h> /* sprintf() */
|
#include <stdio.h> /* sprintf() */
|
#include <stdlib.h> /* kill(), on_exit() */
|
#include <stdlib.h> /* kill(), on_exit() */
|
#include <unistd.h> /* close() */
|
#include <unistd.h> /* close() */
|
#include <fcntl.h> /* O_RDWR */
|
#include <fcntl.h> /* O_RDWR */
|
#include <string.h> /* strchr() */
|
#include <string.h> /* strchr() */
|
|
|
#ifndef __CYGWIN__
|
#ifndef __CYGWIN__
|
#if HAVE_SYS_STROPTS_H
|
#if HAVE_SYS_STROPTS_H
|
#include <sys/stropts.h> /* grantpt(), unlockpt() */
|
#include <sys/stropts.h> /* grantpt(), unlockpt() */
|
#endif
|
#endif
|
#include <libgen.h> /* basename() */
|
#include <libgen.h> /* basename() */
|
#endif /* __CYGWIN__ */
|
#endif /* __CYGWIN__ */
|
|
|
#include <termios.h> /* struct termios and al. */
|
#include <termios.h> /* struct termios and al. */
|
#include <signal.h> /* signal() and al. */
|
#include <signal.h> /* signal() and al. */
|
#include <errno.h> /* errno and al. */
|
#include <errno.h> /* errno and al. */
|
|
|
#include "channel.h"
|
#include "channel.h"
|
#include "generic.h"
|
#include "generic.h"
|
#include "fd.h"
|
#include "fd.h"
|
|
|
struct xterm_channel
|
struct xterm_channel
|
{
|
{
|
struct fd_channel fds;
|
struct fd_channel fds;
|
int pid;
|
int pid;
|
char** argv;
|
char** argv;
|
};
|
};
|
|
|
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
char *basename(const char *filename)
|
char *basename(const char *filename)
|
{
|
{
|
char *p = strrchr (filename, '/');
|
char *p = strrchr (filename, '/');
|
|
|
return p ? p + 1 : (char *) filename;
|
return p ? p + 1 : (char *) filename;
|
}
|
}
|
#endif /* __CYGWIN__ */
|
#endif /* __CYGWIN__ */
|
|
|
static void xterm_close(void * data)
|
static void xterm_close(void * data)
|
{
|
{
|
struct xterm_channel * xt = data;
|
struct xterm_channel * xt = data;
|
|
|
if(!xt)
|
if(!xt)
|
return;
|
return;
|
|
|
if(xt->fds.fdin != -1)
|
if(xt->fds.fdin != -1)
|
close(xt->fds.fdin);
|
close(xt->fds.fdin);
|
|
|
if(xt->pid != -1)
|
if(xt->pid != -1)
|
{
|
{
|
kill(xt->pid, SIGKILL);
|
kill(xt->pid, SIGKILL);
|
waitpid(xt->pid, NULL, 0);
|
waitpid(xt->pid, NULL, 0);
|
}
|
}
|
|
|
if (xt->argv)
|
if (xt->argv)
|
free (xt->argv);
|
free (xt->argv);
|
|
|
xt->fds.fdin = -1;
|
xt->fds.fdin = -1;
|
xt->fds.fdout = -1;
|
xt->fds.fdout = -1;
|
xt->pid = -1;
|
xt->pid = -1;
|
xt->argv = NULL;
|
xt->argv = NULL;
|
|
|
}
|
}
|
|
|
static void xterm_exit(int i, void * data)
|
static void xterm_exit(int i, void * data)
|
{
|
{
|
xterm_close(data);
|
xterm_close(data);
|
}
|
}
|
|
|
#define MAX_XTERM_ARGS 100
|
#define MAX_XTERM_ARGS 100
|
static void * xterm_init(const char * input)
|
static void * xterm_init(const char * input)
|
{
|
{
|
struct xterm_channel * retval = malloc(sizeof(struct xterm_channel));
|
struct xterm_channel * retval = malloc(sizeof(struct xterm_channel));
|
if(retval)
|
if(retval)
|
{
|
{
|
int i;
|
int i;
|
char *arglist;
|
char *arglist;
|
|
|
retval->fds.fdin = -1;
|
retval->fds.fdin = -1;
|
retval->fds.fdout = -1;
|
retval->fds.fdout = -1;
|
retval->pid = -1;
|
retval->pid = -1;
|
|
|
#if defined(HAS_ON_EXIT)
|
#if defined(HAS_ON_EXIT)
|
/* reset cause exit(1), leaving an xterm opened */
|
/* reset cause exit(1), leaving an xterm opened */
|
on_exit(xterm_exit, retval);
|
on_exit(xterm_exit, retval);
|
#endif
|
#endif
|
|
|
i = 2;
|
i = 2;
|
arglist = (char*)input;
|
arglist = (char*)input;
|
retval->argv = malloc(sizeof(char*) * MAX_XTERM_ARGS);
|
retval->argv = malloc(sizeof(char*) * MAX_XTERM_ARGS);
|
if (!retval->argv) {
|
if (!retval->argv) {
|
free(retval);
|
free(retval);
|
return NULL;
|
return NULL;
|
}
|
}
|
/* Assume xterm arguments are separated by whitespace */
|
/* Assume xterm arguments are separated by whitespace */
|
while ((retval->argv[i++] = strtok(arglist, " \t\n"))) {
|
while ((retval->argv[i++] = strtok(arglist, " \t\n"))) {
|
arglist = NULL;
|
arglist = NULL;
|
if (i == MAX_XTERM_ARGS - 1) {
|
if (i == MAX_XTERM_ARGS - 1) {
|
free(retval);
|
free(retval);
|
return NULL;
|
return NULL;
|
}
|
}
|
}
|
}
|
|
|
}
|
}
|
return (void*)retval;
|
return (void*)retval;
|
}
|
}
|
|
|
|
|
|
|
static int xterm_open(void * data)
|
static int xterm_open(void * data)
|
{
|
{
|
#if defined(HAS_GRANTPT) && defined(HAS_UNLOCKPT) && defined(HAS_PTSNAME)
|
#if defined(HAS_GRANTPT) && defined(HAS_UNLOCKPT) && defined(HAS_PTSNAME)
|
struct xterm_channel * xt = data;
|
struct xterm_channel * xt = data;
|
int master, retval;
|
int master, retval;
|
char * slavename;
|
char * slavename;
|
struct termios termio;
|
struct termios termio;
|
char arg[64], * fin;
|
char arg[64], * fin;
|
|
|
if(!data)
|
if(!data)
|
{
|
{
|
errno = ENODEV;
|
errno = ENODEV;
|
return -1;
|
return -1;
|
}
|
}
|
|
|
master = open("/dev/ptmx", O_RDWR);
|
master = open("/dev/ptmx", O_RDWR);
|
|
|
if(master < 0)
|
if(master < 0)
|
return -1;
|
return -1;
|
|
|
grantpt(master);
|
grantpt(master);
|
unlockpt(master);
|
unlockpt(master);
|
slavename = (char*)ptsname(master);
|
slavename = (char*)ptsname(master);
|
|
|
if(!slavename)
|
if(!slavename)
|
{
|
{
|
errno = ENOTTY;
|
errno = ENOTTY;
|
goto closemastererror;
|
goto closemastererror;
|
}
|
}
|
|
|
xt->fds.fdout = xt->fds.fdin = open(slavename, O_RDWR);
|
xt->fds.fdout = xt->fds.fdin = open(slavename, O_RDWR);
|
if(xt->fds.fdout < 0) goto closemastererror;
|
if(xt->fds.fdout < 0) goto closemastererror;
|
|
|
//#if !defined(linux) && !defined(__CYGWIN__)
|
//#if !defined(linux) && !defined(__CYGWIN__)
|
#if defined(I_PUSH)
|
#if defined(I_PUSH)
|
/* Linux does not support STREAMS-style line discipline, even with LiS. */
|
/* Linux does not support STREAMS-style line discipline, even with LiS. */
|
retval = ioctl(xt->fds.fdin, I_PUSH, "ptem");
|
retval = ioctl(xt->fds.fdin, I_PUSH, "ptem");
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
|
|
retval = ioctl(xt->fds.fdin, I_PUSH, "ldterm");
|
retval = ioctl(xt->fds.fdin, I_PUSH, "ldterm");
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
#endif
|
#endif
|
|
|
retval = tcgetattr(xt->fds.fdin, &termio);
|
retval = tcgetattr(xt->fds.fdin, &termio);
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
termio.c_lflag &= ~ECHO;
|
termio.c_lflag &= ~ECHO;
|
retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
|
retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
|
|
xt->pid = fork();
|
xt->pid = fork();
|
|
|
if(xt->pid == -1) goto closeslaveerror;
|
if(xt->pid == -1) goto closeslaveerror;
|
|
|
if(xt->pid == 0)
|
if(xt->pid == 0)
|
{
|
{
|
/* Ctrl-C on sim still kill the xterm, grrr */
|
/* Ctrl-C on sim still kill the xterm, grrr */
|
signal(SIGINT, SIG_IGN);
|
signal(SIGINT, SIG_IGN);
|
|
|
fin = slavename+strlen(slavename)-2;
|
fin = slavename+strlen(slavename)-2;
|
if (strchr(fin, '/' ))
|
if (strchr(fin, '/' ))
|
{
|
{
|
sprintf(arg, "-S%s/%d",
|
sprintf(arg, "-S%s/%d",
|
basename(slavename),
|
basename(slavename),
|
master);
|
master);
|
}
|
}
|
else
|
else
|
{
|
{
|
sprintf(arg, "-S%c%c%d", fin[0], fin[1], master);
|
sprintf(arg, "-S%c%c%d", fin[0], fin[1], master);
|
}
|
}
|
xt->argv[0] = "xterm";
|
xt->argv[0] = "xterm";
|
xt->argv[1] = arg;
|
xt->argv[1] = arg;
|
execvp("xterm", xt->argv);
|
execvp("xterm", xt->argv);
|
write(master, "\n", 1);
|
write(master, "\n", 1);
|
exit(1);
|
exit(1);
|
}
|
}
|
|
|
do retval = read(xt->fds.fdin, &arg, 1);
|
do retval = read(xt->fds.fdin, &arg, 1);
|
while(retval >= 0 && arg[0] != '\n');
|
while(retval >= 0 && arg[0] != '\n');
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
|
|
termio.c_lflag |= ECHO;
|
termio.c_lflag |= ECHO;
|
retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
|
retval = tcsetattr(xt->fds.fdin, TCSADRAIN, &termio);
|
|
|
if(retval < 0) goto closeslaveerror;
|
if(retval < 0) goto closeslaveerror;
|
|
|
return 0;
|
return 0;
|
|
|
closeslaveerror:
|
closeslaveerror:
|
close(xt->fds.fdin);
|
close(xt->fds.fdin);
|
|
|
closemastererror:
|
closemastererror:
|
close(master);
|
close(master);
|
xt->pid = xt->fds.fdin = xt->fds.fdout = -1;
|
xt->pid = xt->fds.fdin = xt->fds.fdout = -1;
|
return -1;
|
return -1;
|
|
|
#else
|
#else
|
/* I don't see how this stuff should be working on a system that doesn't know
|
/* I don't see how this stuff should be working on a system that doesn't know
|
grantpt(), unlockpt(), ptsname(). Mac OS X also does not have /dev/ptmx.
|
grantpt(), unlockpt(), ptsname(). Mac OS X also does not have /dev/ptmx.
|
-hpanther
|
-hpanther
|
*/
|
*/
|
return -1;
|
return -1;
|
#endif
|
#endif
|
}
|
}
|
|
|
struct channel_ops xterm_channel_ops =
|
struct channel_ops xterm_channel_ops =
|
{
|
{
|
init: xterm_init,
|
init: xterm_init,
|
open: xterm_open,
|
open: xterm_open,
|
close: xterm_close,
|
close: xterm_close,
|
read: fd_read,
|
read: fd_read,
|
write: fd_write,
|
write: fd_write,
|
free: generic_free,
|
free: generic_free,
|
};
|
};
|
|
|
/*
|
/*
|
* Local variables:
|
* Local variables:
|
* c-file-style: "linux"
|
* c-file-style: "linux"
|
* End:
|
* End:
|
*/
|
*/
|
|
|
|
|