/* * $Id: fallback.c,v 5.61 2004/04/16 16:58:09 bryan Exp $ * * Copyright conserver.com, 2000 * * Maintainer/Enhancer: Bryan Stansell (bryan@conserver.com) * * Copyright GNAC, Inc., 1998 */ /* * This is a fake library interface to ptyd (mtr&ksb) * * Mike Rowan (mtr@mace.cc.purdue.edu) */ #include #include /* * get a pty for the user * * this has been revamped rather heavily for 8.0.0. i've taken ideas * from the xemacs and openssh distributions to get code that *should* * work on systems i have no access to. thanks to those reference * packages, i think things are ok...hopefully it's true! */ static int #if PROTOTYPES GetPseudoTTY(STRING *slave, int *slaveFD) #else GetPseudoTTY(slave, slaveFD) STRING *slave; int *slaveFD; #endif { #if HAVE_OPENPTY int fd = -1; int sfd = -1; int opty = 0; char *pcName; #if HAVE_SIGACTION sigset_t oldmask, newmask; #else extern RETSIGTYPE FlagReapVirt PARAMS((int)); #endif #if HAVE_SIGACTION sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) Error("GetPseudoTTY(): sigprocmask(SIG_BLOCK): %s", strerror(errno)); #else SimpleSignal(SIGCHLD, SIG_DFL); #endif opty = openpty(&fd, &sfd, NULL, NULL, NULL); #if HAVE_SIGACTION if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) Error("GetPseudoTTY(): sigprocmask(SIG_SETMASK): %s", strerror(errno)); #else SimpleSignal(SIGCHLD, FlagReapVirt); #endif if (opty != 0) { if (fd >= 0) close(fd); if (sfd >= 0) close(sfd); return -1; } if ((char *)0 == (pcName = ttyname(sfd))) { close(fd); close(sfd); return -1; } BuildString((char *)0, slave); BuildString(pcName, slave); *slaveFD = sfd; return fd; #else #if (HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT) || defined(_AIX) int fd = -1; int sfd = -1; char *pcName; #if HAVE_SIGACTION sigset_t oldmask, newmask; #else extern RETSIGTYPE FlagReapVirt PARAMS((int)); #endif int c; /* clone list and idea stolen from xemacs distribution */ static char *clones[] = { "/dev/ptmx", /* Various systems */ "/dev/ptm/clone", /* HPUX */ "/dev/ptc", /* AIX */ "/dev/ptmx_bsd", /* Tru64 */ (char *)0 }; /* try to find the pty allocator */ for (c = 0; clones[c] != (char *)0; c++) { if ((fd = open(clones[c], O_RDWR, 0)) >= 0) break; } if (fd < 0) return -1; #if HAVE_SIGACTION sigemptyset(&newmask); sigaddset(&newmask, SIGCHLD); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) Error("GetPseudoTTY(): sigprocmask(SIG_BLOCK): %s", strerror(errno)); #else SimpleSignal(SIGCHLD, SIG_DFL); #endif #if HAVE_GRANTPT grantpt(fd); /* change permission of slave */ #endif #if HAVE_SIGACTION if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) Error("GetPseudoTTY(): sigprocmask(SIG_SETMASK): %s", strerror(errno)); #else SimpleSignal(SIGCHLD, FlagReapVirt); #endif #if HAVE_UNLOCKPT unlockpt(fd); /* unlock slave */ #endif #if defined(_AIX) if ((pcName = ttyname(fd)) == (char *)0) { close(fd); return -1; } #else # if HAVE_PTSNAME if ((pcName = ptsname(fd)) == (char *)0) { close(fd); return -1; } # else close(fd); return -1; # endif #endif /* go ahead and open the slave */ if ((sfd = open(pcName, O_RDWR, 0)) < 0) { Error("GetPseudoTTY(): open(%s): %s", pcName, strerror(errno)); close(fd); return -1; } BuildString((char *)0, slave); BuildString(pcName, slave); *slaveFD = sfd; return fd; #else /* * Below is the string for finding /dev/ptyXX. For each architecture we * leave some pty's world writable because we don't have source for * everything that uses pty's. For the most part, we'll be trying to * make /dev/ptyq* the "free" pty's. */ /* all the world's a vax ;-) */ static char charone[] = "prstuvwxyzPQRSTUVWq"; static char chartwo[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; static char acMaster[] = "/dev/ptyXX"; static char acSlave[] = "/dev/ttyXX"; static char *pcOne = charone, *pcTwo = chartwo; int fd, sfd, iLoop, iIndex = sizeof("/dev/pty") - 1; char *pcOld1; struct stat statBuf; iLoop = 0; pcOld1 = pcOne; for (;;) { if ('\000' == *++pcTwo) { pcTwo = chartwo; if ('\000' == *++pcOne) { pcOne = charone; if ((pcOld1 == pcOne && ++iLoop > 1) || (iLoop > 32)) return -1; } } acMaster[iIndex] = *pcOne; acMaster[iIndex + 1] = *pcTwo; /* * Remeber we are root - stat the file * to see if it exists before we open it * for read/write - if it doesn't we don't * have any pty's left in the row */ if (-1 == stat(acMaster, &statBuf) || S_IFCHR != (statBuf.st_mode & S_IFMT)) { pcTwo = "l"; continue; } if (0 > (fd = open(acMaster, O_RDWR | O_NONBLOCK, 0))) { continue; } acSlave[iIndex] = *pcOne; acSlave[iIndex + 1] = *pcTwo; if (-1 == access(acSlave, F_OK)) { close(fd); continue; } break; } /* go ahead and open the slave */ if ((sfd = open(acSlave, O_RDWR, 0)) < 0) { Error("GetPseudoTTY(): open(%s): %s", acSlave, strerror(errno)); close(fd); return -1; } BuildString((char *)0, slave); BuildString(acSlave, slave); *slaveFD = sfd; return fd; #endif /* (HAVE_PTSNAME && HAVE_GRANTPT && HAVE_UNLOCKPT) || defined(_AIX) */ #endif /* HAVE_OPENPTY */ } /* * get a pty using the GetPseudoTTY code above */ int #if PROTOTYPES FallBack(char **slave, int *sfd) #else FallBack(slave, sfd) char **slave; int *sfd; #endif { int fd; static STRING *pcTSlave = (STRING *)0; if (pcTSlave == (STRING *)0) pcTSlave = AllocString(); if ((fd = GetPseudoTTY(pcTSlave, sfd)) == -1) { return -1; } if ((*slave) != (char *)0) free(*slave); if (((*slave) = StrDup(pcTSlave->string)) == (char *)0) OutOfMem(); return fd; }