This is pty.c in view mode; [Download] [Up]
#define I_IOCTL #define I_SOCKET #define I_ERRNO #define I_STRING #define I_SYS #include "includes.h" #include "debug.h" #include <string.h> #include <signal.h> #include <sys/stat.h> #include <pwd.h> #ifdef USE_TIOCNOTTY #include <sys/ioctl.h> #endif #ifdef SYSV #include <stropts.h> #if defined(SVR4) || defined(SCO) int grantpt(int); char *ptsname(int); int unlockpt(int); #endif #endif int pty_pid; /* Moved these strings here for compilers which can't handle aggregate auto initialization. Makes open_pty() non-reentrant. HSW 93-01-29 */ #ifdef __hpux static char masterline[]="/dev/ptym/ptyXY"; static char slaveline[]="/dev/pty/ttyXY"; static char *first ="pqrstuv"; #define NBANK 15 #else /* not hpux, and not sgi. */ static char masterline[]="/dev/ptyXY"; static char *first ="pqrstuvwxyz"; static char slaveline[]="/dev/ttyXY"; #define NBANK 16 #endif int open_pty(char *prog) { int masterfd = -1, slavefd, i, pid; int pip[2]; #if !defined(sgi) && !defined(SYSV) && !defined(_AIX) #define SFIRST (sizeof (slaveline) - 3) #define SSECOND (sizeof (slaveline) - 2) /* Ok. Stuff for not sgi. */ #define MFIRST (sizeof (masterline) - 3) #define MSECOND (sizeof (masterline) - 2) char *ptr = first; int c; #else /* sgi || SYSV */ #ifdef SYSV /* Stuff for SYSV */ void (*savesig)(int); char *slaveline; #else /* SYSV */ #ifdef _AIX /* AIX Stuff */ char *slaveline; #else /* AIX */ /* And then finally, sgi stuff. */ char *linetmp; char slaveline[20]; #endif /* AIX */ #endif /* SYSV */ #endif /* sgi || SYSV */ #if !defined(sgi) && !defined(SYSV) && !defined(_AIX) /* get a pseudo tty */ ptr = first; for (c = *ptr; (c = *ptr); ++ptr) { struct stat statbuff; masterline[MFIRST] = c; masterline[MSECOND] = '0'; if (stat (masterline, &statbuff) < 0) continue; /* no pty's on this bank availiable */ i = 0; again: for (; i<NBANK; ++i) { masterline[MSECOND] = "0123456789abcdef"[i]; if ((masterfd = open (masterline, O_RDWR, 0)) > 0) break; } if (i != NBANK) { /* Ok. now check to make sure we can */ /* open the slave as well. */ slaveline[SFIRST] = masterline[MFIRST]; slaveline[SSECOND] = masterline[MSECOND]; if ((slavefd = open (slaveline, O_RDWR, 0)) < 0) { close(masterfd); ++i; goto again; } break; } } if (!c) return -1; DEBUG_FP(stderr, "%s: opened pty master=%s(%u) slave=%s(%u)\n", term_server, masterline, masterfd, slaveline, slavefd); #ifdef SUIDROOT if (fchmod (slavefd, 0622)) return -2; #endif close(slavefd); #else /* sgi || SYSV || _AIX */ #ifdef SYSV if ((masterfd = open("/dev/ptmx", O_RDWR, 0)) < 0) return -1; savesig = signal(SIGCHLD, SIG_DFL); if (grantpt(masterfd) < 0) { close(masterfd); sigset(SIGCHLD, savesig); return -1; } sigset(SIGCHLD, savesig); if (unlockpt(masterfd) < 0) { close(masterfd); return -1; } slaveline = ptsname(masterfd); if (slaveline == NULL) { close(masterfd); return -1; } #else /* SYSV */ #ifdef _AIX if ( (masterfd=open("/dev/ptc",O_RDWR,0600)) < 0 ) return -1; /* No pty's available */ slaveline = ttyname(masterfd); #else /* AIX */ linetmp = _getpty(&masterfd, O_RDWR, 0600, 0); if (linetmp == NULL) return -1; /* no pty's available */ strcpy(slaveline, linetmp); /* Don't check slave - have to assume it's going to work */ #endif /* AIX */ #endif /* SYSV */ #endif /* sgi */ fflush (stdout); if (pipe(pip) <0) return -3; /* unable to pipe */ if ((pid = fork ()) < 0) return -3; /* unable to fork */ if (pid == 0) { /* child. */ /* char ** a, *b[2] = {0, }; Ultrix MIPS compiler chokes */ char ** a, *b[2]; #ifdef LOGIN_SHELL char argv0[1024]; char * progname; int loginshell=0; #endif /*LOGIN_SHELL*/ b[0]=b[1]=NULL; close(0); close(1); close(2); lose_ctty(); /* make it control tty */ if ((slavefd = open (slaveline, O_RDWR, 0)) < 0) { exit(1); } #ifdef USE_VHANGUP signal (SIGHUP, SIG_IGN); vhangup (); signal (SIGHUP, SIG_DFL); if ((slavefd = open (slaveline, O_RDWR, 0)) < 0) { exit(1); } #endif #ifdef SYSV if (ioctl(slavefd, I_PUSH, "ptem") < 0) { exit(1); } if (ioctl(slavefd, I_PUSH, "ldterm") < 0) { exit(1); } #ifdef SVR4 if (ioctl(slavefd, I_PUSH, "ttcompat") < 0) { exit(1); } #endif /* SVR4 */ #endif /* SYSV */ /* ** do a term setup here. */ dup2 (slavefd, 0); dup2 (slavefd, 1); dup2 (slavefd, 2); for (slavefd = 3; slavefd < 64; ++slavefd) { if (slavefd != pip[1]) close(slavefd); } #if !(defined(SVR4)) && !(defined(__hpux)) #ifdef USE_TERMIOS terminal_new(0); #else terminal_restore(0); #endif #endif /* find out what shell to run. */ /* note: technically we should free a, but as we are * in the child who will either exec or exit, we can * neglect this. croutons. */ a = rebuild_arg(prog); if ( !a ) a = b; #ifdef LOGIN_SHELL if ( !a[0] ) { a[0] = getenv("SHELL"); loginshell=1; } if ( !a[0] ) { a[0] = "/bin/sh"; loginshell=1; } progname = a[0]; if (loginshell) { sprintf(argv0, "-%s", strrchr(a[0], '/') ? (char*)(strrchr(a[0], '/') + 1 ) : (char*) a[0]); a[0] = argv0; } #else /*LOGIN_SHELL*/ if ( !a[0] ) a[0] = getenv("SHELL"); if ( !a[0] ) a[0] = "/bin/sh"; #endif /*LOGIN_SHELL*/ /* these printfs are dangerous on NeXT, if the strings are too long, the printfs block! */ printf ("Remote: term %s\r\n", VERSION); printf ("tty %s. Exec %s\r\n", slaveline, a[0]); /* pipe will close upon successful exec */ if (fcntl (pip[1], F_SETFD, 1) == -1) { /* close it now since fcntl failed */ close (pip[1]); } #ifdef LOGIN_SHELL execvp(progname, a); #else execvp(a[0], a); #endif /* write something so parent notes exec failure */ write(pip[1],"",1); close(pip[1]); /* for what it's worth */ printf ("Exec failed %s\r\n", a[0]); exit(1); } /* parent */ close(pip[1]); /* Wait for exec, read blocks until pipe is closed */ if (read(pip[0], (char *) &i, 1) == 0) DEBUG_FP (stderr, "%s: exec apparently succeeded\n", term_server); else DEBUG_FP (stderr, "%s: exec apparently failed\n", term_server); close(pip[0]); set_nonblock(masterfd); /* ioctl(masterfd, TIOCPKY, &one); BSD pty packet mode. */ pty_pid = pid; return masterfd; } static char *argv[4] = {"/bin/sh", "-c", NULL, NULL}; /* non-pty exec */ /* usage is more like rsh, shell can handle compound command */ int open_socket(char *prog) { int i; int soc[2]; int pid; int pip[2]; #ifdef NO_UNIX_DOMAIN if (s_pipe(soc) < 0) return -4; /* no stream pipe */ #else if (socketpair(AF_UNIX, SOCK_STREAM, 0, soc) < 0) return -4; /* no socket */ #endif /* soc[0] is term's end */ set_nonblock(soc[0]); pipe(pip); if ((pid = fork ()) < 0) return -3; /* unable to fork */ if (pid == 0) /* child. */ { close (0); close (1); close (2); lose_ctty(); /* soc[1] is child's end */ dup2 (soc[1], 0); dup2 (soc[1], 1); dup2 (soc[1], 2); for (i = 3; i < 64;++i) if (i != pip[1]) close(i); setbuf(stdout, NULL); /* unpack args */ for (i=0; prog[i] != '\0'; ++i) if (prog[i] == '\377') prog[i] = ' '; argv[2] = prog; /* pipe will close upon successful exec */ if (fcntl (pip[1], F_SETFD, 1) == -1) close (pip[1]); execvp(argv[0], argv); write(pip[1],"",1); close(pip[1]); printf ("Exec failed %s\r\n", argv[0]); exit(1); } /* parent */ close(pip[1]); close(soc[1]); /* Wait for exec, read blocks until pipe is closed */ if (read(pip[0], (char *) &i, 1) == 0) DEBUG_FP (stderr, "%s: exec apparently succeeded\n", term_server); else DEBUG_FP (stderr, "%s: exec apparently failed\n", term_server); close(pip[0]); pty_pid = pid; return soc[0]; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.