?? pty.c
字號:
/* * Interface to BSD-style (SYSV-style if -D_USE_STREAMS) Pseudo-ttys. * * You may want to lookup the pty ioctl's: * * HP-UX Only!: * TIOCTRAP - (disabled default) => no exceptional selects will happen. * = enabled => select detects open and close * slave hangs on open or ioctl until master acks. * non-termio ioctl's detected. * termio ioctl's detected if TIOCTTY disabled. * TIOCTTY - enabled => termio ioctl's valid on slave * termio ioctl's detected only if TIOCMONITOR * - disabled => TIOCTRAP detects termio ioctl's. * TIOCMONITOR - enabled => termio ioctls detected if TIOCTRAP & TIOCTTY * * if TIOCTRAP is enabled, then traps must be ack'd by a TIOCREQCHECK, * TIOCREQSET pair in sequence. * * TIOCSIGMODE - TIOCSIGBLOCK - Caught Slave signals are posponed on ioctl * TIOCSIGABORT - All slave signals return EINTR on ioctl * TIOSIGNORMAL - default, restarted requests => a new ioctl * * None of the above exists on any BSD implemenation I can find. Some mention * is made of setting B0 baudrate causing the master to see a close. */#undef _POSIX_SOURCE /* this is definitely *not* posix source */#include <unistd.h> /* open close */#include <stdlib.h> /* free malloc */#include <stdio.h>#include <string.h> /* strerror */#include <errno.h> /* errno */#include <fcntl.h>#if defined(DGUX)#define _USE_STREAMS#endif#if defined(_USE_STREAMS)#include <sys/stream.h>#include <sys/stropts.h> /* I_PUSH I_FIND */#endif#if defined(__sgi) && !defined(_USE_STREAMS)#include <sys/types.h>#include <sys/stat.h> /* S_IRUSR S_IWUSR */#endif#include "pty.h"#include "log.h"#if defined(_USE_STREAMS) /* { */#define MASTER_PTY "/dev/ptmx" /* __ALPHA __SOLARIS__ DGUX */#define SLAVE_PTY "/dev/pts/n" /* __ALPHA n = 0,1,...,47 */#define PTY_STREAM "ptem" /* see ptem(7) */#define LDIS_STREAM "ldterm" /* SYSV line discipline */#define COMPAT_STREAM "ttycompat" /* tty compatability stream */#if defined(_OSF_SOURCE)#undef LDIS_STREAM#define LDIS_STREAM 0 /* OSF1 includes line discipline */#endif#if defined(__SOLARIS__) /* { */#undef COMPAT_STREAM#define COMPAT_STREAM 0 /* no tty compatability stream reqd *//* * gcc gives an error on using ptsname. The man page is ambiguous. */#if defined(__STDC__) || defined(__cplusplus)extern char *ptsname(int); /* ptsname.3c says in stdio.h; isn't */#elseextern char *ptsname();#endif#endif /* } __SOLARIS__ */#if defined(__sgi)#undef MASTER_PTY#define MASTER_PTY "/dev/ptc"#undef SLAVE_PTY#define SLAVE_PTY "/dev/ttyqn" /* tty[q-z][0-99] */#endif#endif /* } _USE_STREAMS */#if !defined(MASTER_PTY) /* { */#if defined(__UNICOS__) /* { */ #define MASTER_PTY "/dev/pty/0xx" /* 0-132 */#define SLAVE_PTY "/dev/ttyp0xx" /* still incorrect. */#endif/* } UNICOS */#if defined(__sgi) /* { IRIX */#define MASTER_PTY "/dev/ptc" /* /dev/ptc==/dev/ptmx /dev/ptc[1234] */#define SLAVE_PTY "/dev/pts/n" /* n = 0,1,...,12 */ /* IRIX man page also says: /dev/tty[qrstuvwxyz][0-99] */#endif /* } __sgi */#endif /* } !MASTER_PTY */#if !defined(MASTER_PTY)#define USE_DEFAULT#define MASTER_PTY "/dev/ptyxx"#endif#if !defined(SLAVE_PTY)#define SLAVE_PTY "/dev/ttyxx"#endifstatic char defSlave[] = SLAVE_PTY;static char defMaster[] = MASTER_PTY;static char ptynum[] = "0123456789abcdef";static char ptylet[] = "pqrs";#define LOC ((sizeof defMaster) - 2) /* index of last character */extern int debug;extern char *progName;#if defined(_USE_STREAMS) /* { */int pushStream(fd, module) int fd; char *module; { int res; if (module != (char *) 0) { res = ioctl(fd, I_FIND, module); /* see streamio(7) sys/stropt.h */ if (res < 0) { log("%s: ioctl(%d, I_FIND, \"%s\") failed--%s\n", progName, fd, module, ERRMSG); close(fd); return -1; } if (res == 0) { /* module not already pushed */ res = ioctl(fd, I_PUSH, module); if (res < 0) { log("%s: pushStream(%d, \"%s\") failed--%s\n", progName, fd, module, ERRMSG); close(fd); return -1; } } } return fd;}#endif /* } *//* * This funcion is necessary so that re-open's of the slave pty can * make sure to initialize it correctly on some machines which will lose * it if the slave is closed and reopened again. */int openSlavePty(sname, mode) char *sname; int mode; { int res, fd = open(sname, mode, 0); if (fd < 0) { log("%s: openSlavePty(\"%s\", 0%o) failed--%s\n", progName, sname, mode, ERRMSG); return -1; }#if defined(_USE_STREAMS) /* { */ fd = pushStream(fd, PTY_STREAM); if (fd >= 0) { fd = pushStream(fd, LDIS_STREAM); if (fd >= 0) { fd = pushStream(fd, COMPAT_STREAM); } }#endif /* } _USE_STREAMS */ return fd;}/* * Find an available unused pty. Open the master side and slave side. * Return the fd and names for the master and slave sides. * * The reasons you must open the slave are: * - The open must be atomic to opening the master to prevent another * process from grabbing the slave and stealing control. * * - The slave open may be impossible because of permissions. The slave * pty changes ownership when login processes grab it. * * This can cause problems because the slave could become the new controlling * terminal for this process under certain conditions. * HP-UX9.0:pty(7)manPage: * * The slave side of the pty interprets opening or closing the master * side as a modem connection or disconnection on a real terminal. Only * one open to the master side of a pty is permitted. An attempt to open * an already open master side returns -1 and sets the external variable * errno to EBUSY. An attempt to open the master side of a pty that has * a slave with an open file descriptor returns -1 and sets errno to * EBUSY...An ioctl() request made on the slave side of a pty after * the master side is closed returns -1 and sets the external variable * errno to EIO. * * Ultrix:pty(4): The slave device can be opened multiple times, while the * master half can be opened only once. * * Thus, at the instant the open succeeds, we are guarenteed that the slave * side was not open by any other process, and we are the exclusive holder * of the open fd for the master side. * * Two questions remain: What happens if a read occurs on the master * before any process has opened the slave? and, how can the master prevent * multiple opens on the slave? On my machine, the only thing that prevents * a sufficiently determined process from opening the slave (even if it's * already open by another process as the controlling terminal) is the * permissions on the slave pty filename. * * The DEC alpha provides an openpty(3) and forkpty(3) call, but they are not * available on HP-UX or Ultrix. SGI IRIX provides something called _getpty. * * Actually, the slave opening code is not really required. All we want to do * is make sure that the slave has the correct permisisons. */int openPty(mode, slaveName, masterName, size, slaveFd) int mode; char *slaveName, *masterName; unsigned size; int *slaveFd;{ register char *letp = ptylet, *nump; char *sname = defSlave, *mname = defMaster; int fd = -1, res;#if defined(__SOLARIS__) || defined(DGUX) /* { */ fd = open(mname, mode); if (debug > 1) { log("%s: open(\"%s\", 0%o) returned %d\n", progName, mname, mode, fd); } if (fd >= 0) { /* grantpt does chmod(mfd, 0620); chown(mfd, geteuid()), via a fork. * Failure of grantpt is not usually fatal; if we're root already * then we'll do it later explicitly anyway */ res = grantpt(fd); if (debug > 1) { log("%s: grantpt(%d) returned %d\n", progName, fd, res); } res = unlockpt(fd); /* clear lock on slave w/master fd for open() */ if (debug > 1) { log("%s: unlockpt(%d) returned %d\n", progName, fd, res); } if (res < 0) goto ptyFail; sname = ptsname(fd); /* <stdio.h> "/dev/pts/N", N = non-negative int */ if (sname == 0) { log("%s: ptsname(%d) failed--%s\n", progName, fd); goto ptyFail; } if (debug > 1) { log("%s: ptsname(%d) returned \"%s\"\n", progName, fd, sname); } if (slaveFd != (int *) 0) { *slaveFd = openSlavePty(sname, mode); if (*slaveFd < 0) goto ptyFail; } }#endif /* } __SOLARIS__ || DGUX */#if defined(__sgi) && !defined(_USE_STREAMS) /* { */ sname = _getpty(&fd, mode, S_IRUSR | S_IWUSR | S_IWGRP, 1); if (sname == 0) { log("%s: _getpty(&fd, %o, %o, 1) failed--%s\n", progName, mode, S_IRUSR | S_IWUSR | S_IWGRP, ERRMSG); goto ptyFail; } if (slaveFd != (int *) 0) { *slaveFd = openSlavePty(sname, mode); if (*slaveFd <= 0) goto ptyFail; }#endif /* } __sgi */#if defined(USE_DEFAULT) /* { */ do { mname[LOC-1] = sname[LOC-1] = *letp; nump = ptynum; do { mname[LOC] = sname[LOC] = *nump; fd = open(mname, mode, 0); if (fd >= 0) { if (slaveFd == (int *) 0) goto gotPty; *slaveFd = openSlavePty(sname, mode); if (*slaveFd >= 0) goto gotPty; close(fd); fd = -1; } } while (*++nump != '\0'); } while (*++letp != '\0');#endif /* } USE_DEFAULT */gotPty: if (fd >= 0) { if (masterName != (char *) 0) { strncpy(masterName, mname, size); } if (slaveName != (char *) 0) { strncpy(slaveName, sname, size); } }ptyRtn: return fd;ptyFail: close(fd); fd = -1; goto ptyRtn;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -