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.