OpenCores
URL https://opencores.org/ocsvn/openrisc_me/openrisc_me/trunk

Subversion Repositories openrisc_me

[/] [openrisc/] [trunk/] [or1ksim/] [peripheral/] [channels/] [xterm.c] - Rev 480

Go to most recent revision | Compare with Previous | Blame | View Log

/* xterm.c -- Definition of functions and structures for 
   peripheral to communicate with host through an xterm.
   Inspired from SWI-Prolog by Jan Wielemaker (GPL too)
   even if there is really few in common.
 
   Copyright (C) 2002 Richard Prescott <rip@step.polymtl.ca>
   Copyright (C) 2008 Embecosm Limited
 
   Contributor Jeremy Bennett <jeremy.bennett@embecosm.com>
 
   This file is part of OpenRISC 1000 Architectural Simulator.
 
   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 the Free
   Software Foundation; either version 3 of the License, or (at your option)
   any later version.
 
   This program is distributed in the hope that it will be useful, but WITHOUT
   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
   more details.
 
   You should have received a copy of the GNU General Public License along
   with this program.  If not, see <http://www.gnu.org/licenses/>. */
 
 
/* This program is commented throughout in a fashion suitable for processing
   with Doxygen. */
 
 
/* Autoconf and/or portability configuration */
#include "config.h"
#include "port.h"
 
/* System includes */
#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
#endif
 
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <termios.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
 
#if HAVE_SYS_STROPTS_H
#include <sys/stropts.h>	/* I_PUSH ioctl */
#endif
 
#if HAVE_BASENAME
#include <libgen.h>		/* basename() */
#endif
 
/* Package includes */
#include "channel.h"
#include "generic.h"
#include "fd.h"
 
/*! Data structure to represent the connection to the xterm */
struct xterm_channel
{
  struct fd_channel fds;
  int pid;
  char **argv;
};
 
/* Forward declaration of static functions */
static void  xterm_close (void *data);
static void *xterm_init (const char *input);
static int   xterm_open (void *data);
 
/*! Global data structure with the xterm interface functions */
struct channel_ops  xterm_channel_ops = {
	.init  = xterm_init,
	.open  = xterm_open,
	.close = xterm_close,
	.read  = fd_read,
	.write = fd_write,
	.free  = generic_free,
};
 
 
#if !(HAVE_BASENAME)
static char *
basename (const char *filename)
{
  char *p = strrchr (filename, '/');
 
  return p ? p + 1 : (char *) filename;
}
#endif /* HAVE_BASENAME */
 
static void
xterm_close (void *data)
{
  struct xterm_channel *xt = data;
 
  if (!xt)
    return;
 
  if (xt->fds.fdin != -1)
    close (xt->fds.fdin);
 
  if (xt->pid != -1)
    {
      kill (xt->pid, SIGKILL);
      waitpid (xt->pid, NULL, 0);
    }
 
  if (xt->argv)
    free (xt->argv);
 
  xt->fds.fdin = -1;
  xt->fds.fdout = -1;
  xt->pid = -1;
  xt->argv = NULL;
 
}
 
#if defined(HAVE_ON_EXIT)
static void
xterm_exit (int i, void *data)
{
  xterm_close (data);
}
#endif
 
#define MAX_XTERM_ARGS 100
static void *
xterm_init (const char *input)
{
  struct xterm_channel *retval = malloc (sizeof (struct xterm_channel));
  if (retval)
    {
      int i;
      char *arglist;
 
      retval->fds.fdin = -1;
      retval->fds.fdout = -1;
      retval->pid = -1;
 
#if defined(HAVE_ON_EXIT)
      /* reset cause exit(1), leaving an xterm opened */
      on_exit (xterm_exit, retval);
#endif
 
      i = 2;
      arglist = (char *) input;
      retval->argv = malloc (sizeof (char *) * MAX_XTERM_ARGS);
      if (!retval->argv)
	{
	  free (retval);
	  return NULL;
	}
      /* Assume xterm arguments are separated by whitespace */
      while ((retval->argv[i++] = strtok (arglist, " \t\n")))
	{
	  arglist = NULL;
	  if (i == MAX_XTERM_ARGS - 1)
	    {
	      free (retval);
	      return NULL;
	    }
	}
 
    }
  return (void *) retval;
}
 
 
 
static int
xterm_open (void *data)
{
#if defined(HAVE_GRANTPT) && defined(HAVE_UNLOCKPT) && defined(HAVE_PTSNAME)
  struct xterm_channel *xt = data;
  int master, retval;
  char *slavename;
  struct termios termio;
  char arg[64], *fin;
 
  if (!data)
    {
      errno = ENODEV;
      return -1;
    }
 
  master = open ("/dev/ptmx", O_RDWR);
 
  if (master < 0)
    return -1;
 
  grantpt (master);
  unlockpt (master);
  slavename = (char *) ptsname (master);
 
  if (!slavename)
    {
      errno = ENOTTY;
      goto closemastererror;
    }
 
  xt->fds.fdout = xt->fds.fdin = open (slavename, O_RDWR);
  if (xt->fds.fdout < 0)
    goto closemastererror;
 
#if HAVE_DECL_I_PUSH
  /* These modules must be pushed onto the stream for some non-Linux and
     non-Cygwin operating systems. */
  retval = ioctl (xt->fds.fdin, I_PUSH, "ptem");
  if (retval < 0)
    goto closeslaveerror;
 
  retval = ioctl (xt->fds.fdin, I_PUSH, "ldterm");
  if (retval < 0)
    goto closeslaveerror;
#endif
 
  retval = tcgetattr (xt->fds.fdin, &termio);
  if (retval < 0)
    goto closeslaveerror;
  termio.c_lflag &= ~ECHO;
  retval = tcsetattr (xt->fds.fdin, TCSADRAIN, &termio);
  if (retval < 0)
    goto closeslaveerror;
 
  xt->pid = fork ();
 
  if (xt->pid == -1)
    goto closeslaveerror;
 
  if (xt->pid == 0)
    {
      /* Ctrl-C on sim still kill the xterm, grrr */
      signal (SIGINT, SIG_IGN);
 
      fin = slavename + strlen (slavename) - 2;
      if (strchr (fin, '/'))
	{
	  sprintf (arg, "-S%s/%d", basename (slavename), master);
	}
      else
	{
	  sprintf (arg, "-S%c%c%d", fin[0], fin[1], master);
	}
      xt->argv[0] = "xterm";
      xt->argv[1] = arg;
      execvp ("xterm", xt->argv);
      if (write (master, "\n", 1) < 0)	/* Don't ignore result */
	{
	  printf ("ERROR: xterm: write failed\n");
	}
      exit (1);
    }
 
  do
    retval = read (xt->fds.fdin, &arg, 1);
  while (retval >= 0 && arg[0] != '\n');
  if (retval < 0)
    goto closeslaveerror;
 
  termio.c_lflag |= ECHO;
  retval = tcsetattr (xt->fds.fdin, TCSADRAIN, &termio);
 
  if (retval < 0)
    goto closeslaveerror;
 
  return 0;
 
closeslaveerror:
  close (xt->fds.fdin);
 
closemastererror:
  close (master);
  xt->pid = xt->fds.fdin = xt->fds.fdout = -1;
  return -1;
 
#else
  /* 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.
     -hpanther
   */
  return -1;
#endif
}
 

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.