This is etermSupport.c in view mode; [Download] [Up]
#include <stdio.h>
#include <libc.h>
#include <signal.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include "etermSupport.h"
/* Some random lab's phone number. Ask Tom Lord */
#define FIB20 6765
extern int errno;
/*
* Given the current environment, give us a new environment suitable
* for an emacs process with an event server on port 'eventportno'
*/
char **patch_env (char **currentEnv, int eventportno)
{
static char term[] = "TERM=eterm";
static char termcap[] = "TERMCAP=69|eterm|Terminal emulator for Gnu-emacs:co#80:li#24:cm=^u%d^u%d.:IC=^u%d_:DC=^u%d^d:AL=^u%d^o:DL=^u%d^k:bc=^b:bl=^g:cd=^[k:ce=^k:ch=^u%d.:cl=^[c:cr=^a:do=^n:im=^i:ei=^i:le=^b:mi:ms:nd=^f:nl=^j:se=^s:so=^s:up=^p:am:km:";
char *eventhost;
static char eventport[80];
char ** newEnv;
int envSize,x,y;
char hostname[1024];
if (gethostname(hostname, sizeof(hostname)) == -1) {
perror("gethostname");
exit(1);
}
eventhost = malloc(strlen(hostname)+12);
strcpy(eventhost, "EVENT_HOST=");
strcat(eventhost, hostname);
sprintf(eventport, "EVENT_PORT=%d", eventportno);
for (envSize = 0; currentEnv[ envSize ] != NULL; envSize++);
newEnv = (char **)malloc( sizeof( char * ) * (envSize + 5) );
for (x = y = 0; x < envSize; x++)
if (strncmp( currentEnv[x], "TERM=", 5 ) &&
strncmp( currentEnv[x], "TERMCAP=", 8 ) &&
strncmp( currentEnv[x], "EVENT_HOST=", 11) &&
strncmp( currentEnv[x], "EVENT_PORT=", 11))
newEnv[ y++ ] = currentEnv[ x ];
newEnv[ y++ ] = term;
newEnv[ y++ ] = termcap;
newEnv[ y++ ] = eventhost;
newEnv[ y++ ] = eventport;
newEnv[ y ] = NULL;
return newEnv;
}
/*
* Create the event server socket for an emacs process.
* Store the port number in the int ponted to by eventportno
*/
int create_server_socket(int *eventportno)
{
int EventServerSocket;
struct sockaddr_in name;
int portno = FIB20;
if ((EventServerSocket = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP )) < 0) {
perror("socket");
exit(1);
}
while (portno < FIB20 + 100) {
name.sin_family = AF_INET;
name.sin_port = htons(portno);
name.sin_addr.s_addr = INADDR_ANY;
if (bind(EventServerSocket, (struct sockaddr *)&name, sizeof(name)) == -1) {
portno++;
continue;
}
if (listen(EventServerSocket, 1) == -1) {
perror("listen");
exit(1);
}
*eventportno = portno;
return EventServerSocket;
}
perror("bind");
exit(1);
}
/*
* Accept a connection on an event server socket
*/
int accept_server_connection(int serversocket)
{
int s;
struct sockaddr_in name;
int namelen = sizeof(name);
if ((s = accept(serversocket, (struct sockaddr *)&name, &namelen)) == -1)
return -1;
return s;
}
void child_setup_tty (int out)
{
struct sgttyb s;
ioctl (out, TIOCGETP, &s);
s.sg_flags |= (ECHO | CRMOD);
ioctl (out, TIOCSETN, &s);
}
void setup_tty (int out)
{
struct sgttyb s;
ioctl (out, TIOCGETP, &s);
s.sg_flags &= ~(ECHO);
s.sg_flags |= RAW;
ioctl (out, TIOCSETN, &s);
}
// Open an available pty, putting descriptor in *ptyv, and return the
// file name of the corresponding tty. Return 0 if none available.
char ptyname[24];
char * pty (int *ptyv)
{
struct stat stb;
register c, i;
for (c = 'p'; c <= 'q'; c++)
for (i = 0; i < 16; i++)
{
sprintf (ptyname, "/dev/pty%c%x", c, i);
if (stat (ptyname, &stb) < 0)
return 0;
*ptyv = open (ptyname, O_RDWR | O_NDELAY, 0);
if (*ptyv >= 0)
{
/* check to make certain that both sides are available
this avoids a nasty yet stupid bug in rlogins */
ptyname[5] = 't';
if (access (ptyname, 6) != 0)
{
close (*ptyv);
continue;
}
/*
* If the following statement is included,
* then a 0 length record is EOT, but no other
* control characters can be sent down the pty
* (e.g., ^S/^Q, ^O, etc.). If it is not
* included, then sending ^D down the pty-pipe
* makes a pretty good EOF.
*/
return ptyname;
}
}
return 0;
}
// Grab a pty/tty pair for running a child process.
void create_channel(int *master, int *slave)
{
int MasterChannel, ShellChannel;
int pid;
char *ttyname;
pid = getpid ();
if (setpgrp (0, pid) < 0) perror("setpgrp");
/* remove the current controling terminal -- will create a new one */
{
int fd;
fd = open ("/dev/tty", O_RDWR, 0);
if (fd >= 0)
{
if (ioctl (fd, TIOCNOTTY, NULL) < 0) perror ("ioctl (TIOCNOTTY)");
close (fd);
}
}
ttyname = pty(&MasterChannel);
/* adjust terminal driver for Master Channel */
setup_tty(MasterChannel);
if (ttyname)
{
ShellChannel = open(ttyname, O_RDWR, 0);
if (ShellChannel < 0) perror("Shell Channel");
}
*master = MasterChannel;
*slave = ShellChannel;
}
/*
* Reap zombie processes. If any child processes stopped themselves,
* give them a kick in the pants.
*/
static void ShellDone ()
{
int pid;
union wait stat;
while ((pid = wait3( &stat, WUNTRACED | WNOHANG, 0 )) > 0) {
if (WIFSTOPPED(stat))
kill(pid,SIGCONT);
}
}
void fork_shell (char *name, char **args, char **env, int channel)
{
int pid;
signal(SIGCLD, ShellDone);
signal(SIGTTOU, SIG_IGN);
if ((pid = fork ()) < 0)
{
fprintf (stderr, "Fork failed\n");
exit (1);
}
if (pid == 0) {
int cpid;
cpid = getpid ();
setpriority(0, cpid, 0);
if (setpgrp (0, 0) < 0) perror ("setpgrp");
if (channel >= 0) close(channel);
channel = open(ptyname, O_RDWR, 0);
vhangup();
/* adjust terminal driver for Shell Channel */
child_setup_tty(channel);
dup2(channel, 0);
dup2(channel, 1);
dup2(channel, 2);
close(channel);
execve (name, args, env);
_exit (1);
}
}
/*
* Create the information necessary for handling a new display.
* The return value is the "rock" that should be given to
* DPSAddFD() as the value to give to input_from_apps()
*
* (A "rock" is the CMU term for an item you hide information
* underneath.)
*/
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.