📄 tty.c
字号:
/* * @(#) tty.c RCS: $Revision: 1.10 $ $Date: 95/03/02 12:21:21 $ * * Functions to handle terminal console I/O: * * askTty - emit a prompt and read in a passphrase with echo disabled * mkCtrlTty - make the specified device the controlling terminal * setTtyEcho - enable/disable echoing of typed characters * setTtyAscii - Put terminal in ASCII input mode (echo, backspace etc) * setTtyBin - Put terminal into transparent mode (no character interperation) * isTty - query to see if device is a terminal * openCtty - open the controlling terminal * restoreTty - restore the original state of the terminal */#if !defined(_POSIX_SOURCE)#define _POSIX_SOURCE#endif/* * <ioctl.h> is necessary for machines which require it for explicitly making * a tty the controlling terminal. This isn't very many. Unfortunately, * <ioctl.h> won't export TIOCSCTTY if _POSIX_SOURCE is defined on some * machines. To make this situation even worse, #include files are notoriously * sensitve to order; be very careful before changing it. */#if defined(__ALPHA) || defined(__MIPS) || defined(__bsdi__)#if defined(__MIPS)#undef _POSIX_SOURCE#endif#include <sys/ioctl.h> /* TIOCNOTTY TIOCSCTTY */#if defined(__MIPS)#define _POSIX_SOURCE#endif#endif#include <unistd.h> /* open ctermid */#include <stdlib.h> /* exit */#include <signal.h>#include <stdio.h>#include <sys/types.h> /* for fcntl.h *//* * BSDI's BSD/386 has no way to #define ONLCR in <termios.h> if__POSIX_SOURCE * is defined. Also, its value is not 0x04 as it is on all other machines that * have this problem. POSIX really blew it by not having a standard #define to * enable non-posix symbol visability. I can't count on tty drivers enabling * ONLCR when OPOST in enabled either. I also can't just do this for all * machines because HP-UX will make termios.h empty if I undef _POSIX SOURCE. */#if defined(__bsdi__)#undef _POSIX_SOURCE#endif#include <termios.h> /* tcsetattr ONLCR */#if defined(__bsdi__)#define _POSIX_SOURCE#endif#include <fcntl.h>#include <string.h> /* memcpy */#include <errno.h> /* ENOTTY */#include "deslogin.h"#include "log.h"#include "tty.h"#include "posignal.h"extern int debug;/* * Return 1 if the specified fd is associated with a tty device * 0 if not, * -1 if failure */int isTty(fd) int fd;{ struct termios modes; register int res = (tcgetattr(fd, &modes) == 0); if (res == 0) { if (errno != ENOTTY) { --res; } } return res;}int openCtty(){ char cttyName[L_ctermid]; int ctty; cttyName[0] = '\0'; /* shouldn't be necessary, but I'm paranoid */ /* * Linux fails to declare "exter char *ctermid()". Add it here if you * get a warning. Linux's <unistd.h> needs to be fixed. */ ctty = open(ctermid(cttyName), O_RDWR); /* in Posix <unistd.h> */ if (debug) { log("%s: (openCtty) open(ctermid = \"%s\") returned fd %d\n", progName, cttyName, ctty); } if (ctty < 0) { log("%s: open(\"%s\", O_RDWR) failed -- %s\n", progName, cttyName, ERRMSG); } return ctty;}int restoreTty(ttyfd, oldmodes) int ttyfd; struct termios *oldmodes;{ int res; res = tcsetattr(ttyfd, TCSANOW, oldmodes); if (res < 0) { log("%s: tcsetattr to fd %d failed -- %s\n", progName, ttyfd, ERRMSG); exit(1); } return 0;}/* * Set the specified tty device to binary (with error report) * Put the original modes in oldmodes. */int setTtyBin(ttyfd, oldmodes) int ttyfd; struct termios *oldmodes;{ struct termios modes; int res; if (oldmodes != (struct termios *) 0) { res = tcgetattr(ttyfd, &modes); if (res < 0) { log("%s: tcgetattr on fd %d failed--%s\n", progName, ttyfd, ERRMSG); exit(1); } memcpy(oldmodes, &modes, sizeof (struct termios)); } modes.c_cflag = CS8 | CREAD; modes.c_iflag = BRKINT; modes.c_oflag &= ~OPOST; /* Don't damage other bits */ modes.c_lflag = 0; modes.c_cc[VMIN] = 1; modes.c_cc[VTIME] = 0; res = cfsetospeed(&modes, B9600); if (res < 0) { log("%s: unsupported speed -- B9600\n", progName); exit(1); } res = tcsetattr(ttyfd, TCSANOW, &modes); if (res < 0) { log("%s: tcsetattr to fd %d failed -- %s\n", progName, ttyfd, ERRMSG); exit(1); } return 0;}/* * Set specified tty to interactive mode */int setTtyAscii(ctty) int ctty;{ int res; struct termios modes; res = tcgetattr(ctty, &modes); if (res < 0) { log("%s: tcgetattr failed --%s\n", progName, ERRMSG); exit(1); } modes.c_cflag = CS8 | CREAD | HUPCL; modes.c_iflag = ICRNL | BRKINT | IXON; modes.c_lflag = ICANON | ECHO | ECHOE | ISIG; modes.c_oflag |= OPOST; modes.c_oflag |= ONLCR; /* ONLCR is not POSIX, but we must set it! */ modes.c_cc[VERASE] = '\b'; modes.c_cc[VINTR] = '\003'; res = cfsetospeed(&modes, B9600); if (res < 0) { log("%s: unsupported speed -- B9600\n", progName); exit(1); } res = tcsetattr(ctty, TCSANOW, &modes); if (debug > 1) { log("%s: tcsetattr returned %d\n", progName, res); } if (res < 0) { log("%s: tcsetattr failed -- %s\n", progName, ERRMSG); exit(1); } return 0;}/* * Set tty echo on(1) or off(0); returns previous setting or -1 */int setTtyEcho(fd, echo) int fd; int echo;{ register int res, oldecho; struct termios modes; res = tcgetattr(fd, &modes); if (res < 0) return -1; oldecho = ((modes.c_lflag & ECHO) != 0); if (echo) { modes.c_lflag |= ECHO; } else { modes.c_lflag &= ~ECHO; } res = tcsetattr(fd, TCSANOW, &modes); if (res < 0) return -2; return oldecho;}/* * Make the specified fd the controlling terminal. * * Some machines require an explicit call. Only the session leader can * do this successfully. Returns: >=0 success, < 0 failure w/errno set. * * If flag is non-zero, make fd a controlling terminal, otherwise make it * not the controlling terminal. */int mkCtrlTty(fd, flag) int fd, flag;{ int res = 0; pid_t pid;#if defined(__ALPHA) || defined(__bsdi__) /* OSF1(DECalpha)tty(7): * In earlier versions of UNIX systems, a controlling terminal was * implicitly assigned to a process if, at the time an open was done on * the terminal, the terminal was not the controlling terminal for any * process, and if the pro-cess doing the open did not have a controlling * terminal. In this version of UNIX, in accordance with POSIX 1003.1, * a process must be a session leader to allocate a controlling terminal. * In addition, the allocation is now done explicitly with a call to * ioctl(). (This implies that the O_NOCTTY flag to the open() * function is ignored.) */ if (flag) { res = ioctl(fd, TIOCSCTTY,0); } else { res = ioctl(fd, TIOCNOTTY,0); }#endif#if defined(__MIPS) /* { */ /* ULTRIX(MIPS)tty(4): * If a process that has no control terminal opens a terminal file, then * that terminal file becomes the control terminal for that process. The * control terminal is thereafter inherited by a child process during a * fork(2), even if the control terminal is closed. */ if (flag) { res = 0; /* Hack for DEC MIPS Ultrix 4.1.2 and 4.1.3 */ } else { res = ioctl(fd, TIOCNOTTY,0); }#endif /* } */#if defined(__SOLARIS__) /* { */ pid = getpgrp(); if (pid < 0) { log("%s: (mkCtrlTty) getpgrp failed -- %s\n", progName, ERRMSG); } else { res = ioctl(fd, TIOCSPGRP, &pid); if (res < 0) { log("%s: (mkCtrlTty) ioctl(%d, TIOCSPGRP, %d) failed -- %s\n", progName, fd, pid, ERRMSG); } }#endif /* } */ if (debug > 1) { log("%s: (mkCtrlTty)(%d)=%d\n", progName, fd, res); } return res;}int oldEcho = 1;int ttyfd = -1;void restoreEcho(sig) int sig;{ if (ttyfd >= 0) { setTtyEcho(ttyfd, oldEcho); close(ttyfd); } exit(0);}/* * Read in a passphrase terminated by '\n' of upto size characters from the * controlling terminal with echo disabled. The phrase strips the '\n', * and appends a '\0'. Intercepts interrupt signal and restores echo. */int askTty(prompt, str, size, echo) char *prompt; char *str; unsigned size; int echo;{ unsigned len = strlen(prompt); register int count; register char *chp = str; register int res = -1; char ch; pfv oldsigint; ttyfd = openCtty(); if (ttyfd == -1) return -1; oldsigint = posignal(SIGINT, restoreEcho); oldEcho = setTtyEcho(ttyfd, echo); count = write(ttyfd, prompt, len); if (count != len) return -1; if (size != 0) do { count = read(ttyfd, &ch, 1); if (count == 0) break; if (count != 1) break; if (ch == '\n') break; *chp++ = ch; } while (--size != 0); if (count >= 0) { res = chp - str; } *chp = '\0'; if (!echo) { count = write(ttyfd, "\n", 1); /* goto next line */ } oldEcho = setTtyEcho(ttyfd, oldEcho); posignal(SIGINT, oldsigint); close(ttyfd); ttyfd = -1; return res;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -