From 1cc9f22072de1d314a67387aac57740fb25c5258 Mon Sep 17 00:00:00 2001 From: Tar Committer Date: Thu, 4 May 2006 21:40:56 +0000 Subject: Imported from rancid-2.3.2a4.tar.gz. --- bin/hpuifilter.c | 662 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 485 insertions(+), 177 deletions(-) (limited to 'bin/hpuifilter.c') diff --git a/bin/hpuifilter.c b/bin/hpuifilter.c index 4747299..a13c223 100644 --- a/bin/hpuifilter.c +++ b/bin/hpuifilter.c @@ -1,5 +1,5 @@ /* - * $Id: hpuifilter.c,v 1.21 2005/06/14 20:20:43 heas Exp $ + * $Id: hpuifilter.c,v 1.30 2005/09/29 16:58:16 heas Exp $ * * Copyright (C) 1997-2004 by Terrapin Communications, Inc. * All rights reserved. @@ -21,53 +21,117 @@ * point of hpfilter is to filter all the bloody vt100 (curses) escape codes * that the HP procurve switches belch out, which are a real bitch to handle * in hlogin. + * + * Modified openpty() from NetBSD: + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. */ -#define DFLT_TO 60 /* default timeout */ #include "config.h" #include "version.h" +#if HAVE_UNISTD_H +# include +#endif + #include #include #include +#include +#if HAVE_PTY_H +# include +#endif +#include #include +#if HAVE_STRING_H +# if !STDC_HEADERS && HAVE_MEMORY_H +# include +# endif +# include +#endif +#if HAVE_STRINGS_H +# include +#endif +#if HAVE_PTMX && HAVE_STROPTS_H +# include +#endif +#include +#include #include -#include - #include +#if HAVE_UTIL_H +# include +#endif #define BUFSZ (LINE_MAX * 2) -char *progname; -int debug = 0; +char **environ, + *progname; +int child, + debug, + drain, + timeo = 5; /* default timeout */ int filter __P((char *, int)); +RETSIGTYPE reapchild __P((void)); +#if !HAVE_OPENPTY +int openpty(int *, int *, char *, struct termios *, + struct winsize *); +#endif +RETSIGTYPE sighdlr __P((int)); +#if !HAVE_UNSETENV +int unsetenv __P((const char *)); +#endif void usage __P((void)); void vers __P((void)); -RETSIGTYPE reapchild __P((void)); int -main(int argc, char **argv) +main(int argc, char **argv, char **ev) { extern char *optarg; extern int optind; char ch, hbuf[BUFSZ], /* hlogin buffer */ - *hbufp, + ptyname[FILENAME_MAX + 1], tbuf[BUFSZ], /* telnet/ssh buffer */ *tbufp; int bytes, /* bytes read/written */ - child, - r[2], /* recv pipe */ - s[2]; /* send pipe */ + devnull, + rval = EX_OK, + ptym, /* master pty */ + ptys; /* slave pty */ ssize_t hlen = 0, /* len of hbuf */ tlen = 0; /* len of tbuf */ - struct timeval to = { DFLT_TO, 0 }; - fd_set rfds, /* select() */ - wfds; + struct pollfd pfds[3]; struct termios tios; + environ = ev; + /* get just the basename() of our exec() name and strip a .* off the end */ if ((progname = strrchr(argv[0], '/')) != NULL) progname += 1; @@ -76,11 +140,16 @@ main(int argc, char **argv) if (strrchr(progname, '.') != NULL) *(strrchr(progname, '.')) = '\0'; - while ((ch = getopt(argc, argv, "dhv")) != -1 ) + while ((ch = getopt(argc, argv, "dhvt:")) != -1 ) switch (ch) { case 'd': debug++; break; + case 't': + timeo = atoi(optarg); + if (timeo < 1) + timeo = 1; + break; case 'v': vers(); return(EX_OK); @@ -95,26 +164,40 @@ main(int argc, char **argv) return(EX_USAGE); } - /* reap our children */ - signal(SIGCHLD, (void *) reapchild); - signal(SIGHUP, (void *) reapchild); - signal(SIGINT, (void *) reapchild); - signal(SIGTERM, (void *) reapchild); + unsetenv("DISPLAY"); - /* create 2 pipes for send/recv and then fork and exec telnet/ssh */ + /* allocate pty for telnet/ssh, then fork and exec */ for (child = 3; child < 10; child++) close(child); - if (pipe(s) || pipe(r)) { - fprintf(stderr, "%s: pipe() failed: %s\n", progname, + if (openpty(&ptym, &ptys, ptyname, NULL, NULL)) { + fprintf(stderr, "%s: could not allocate pty: %s\n", progname, strerror(errno)); return(EX_TEMPFAIL); } + /* make the pty raw */ + if (tcgetattr(ptys, &tios)) { + fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } + tios.c_lflag &= ~ECHO; + tios.c_lflag &= ~ICANON; +#ifdef VMIN + tios.c_cc[VMIN] = 1; + tios.c_cc[VTIME] = 0; +#endif + if (tcsetattr(ptys, TCSANOW, &tios)) { + fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, + strerror(errno)); + return(EX_OSERR); + } - /* if a tty, make it raw as the hp echos _everything_, including + /* + * if a tty, make it raw as the hp echos _everything_, including * passwords. */ - if (isatty(0)) { - if (tcgetattr(0, &tios)) { + if (isatty(fileno(stdin))) { + if (tcgetattr(fileno(stdin), &tios)) { fprintf(stderr, "%s: tcgetattr() failed: %s\n", progname, strerror(errno)); return(EX_OSERR); @@ -125,164 +208,249 @@ main(int argc, char **argv) tios.c_cc[VMIN] = 1; tios.c_cc[VTIME] = 0; #endif - if (tcsetattr(0, TCSANOW, &tios)) { + if (tcsetattr(fileno(stdin), TCSANOW, &tios)) { fprintf(stderr, "%s: tcsetattr() failed: %s\n", progname, strerror(errno)); return(EX_OSERR); } } + /* zero the buffers */ + memset(hbuf, 0, BUFSZ); + memset(tbuf, 0, BUFSZ); + + /* reap our children, must be set-up *after* openpty() */ + signal(SIGCHLD, (void *) reapchild); + if ((child = fork()) == -1) { - fprintf(stderr, "%s: fork() failed: %s\n", progname, - strerror(errno)); + fprintf(stderr, "%s: fork() failed: %s\n", progname, strerror(errno)); return(EX_TEMPFAIL); } - /* zero the buffers */ - bzero(hbuf, BUFSZ); - bzero(tbuf, BUFSZ); - if (child == 0) { - /* close the parent's side of the pipes; we write r[1], read s[0] */ - close(s[1]); - close(r[0]); + signal(SIGCHLD, SIG_DFL); + /* close the master pty & std* inherited from the parent */ + close(ptym); + setsid(); + if (ptys != 0) + close(0); + if (ptys != 1) + close(1); + if (ptys != 2) + close(2); +#ifdef TIOCSCTTY + if (ioctl(ptys, TIOCSCTTY, NULL) == -1) { + snprintf(ptyname, FILENAME_MAX, "%s: could not set controlling " + "tty: %s\n", progname, strerror(errno)); + write(ptys, ptyname, strlen(ptyname)); + return(EX_OSERR); + } +#endif + /* close stdin/out/err and attach them to the pipes */ - if (dup2(s[0], 0) == -1 || dup2(r[1], 1) == -1 || dup2(r[1], 2) == -1) { - fprintf(stderr, "%s: dup2() failed: %s\n", progname, - strerror(errno)); + if (dup2(ptys, 0) == -1 || dup2(ptys, 1) == -1 || dup2(ptys, 2) == -1) { + snprintf(ptyname, FILENAME_MAX, "%s: dup2() failed: %s\n", progname, + strerror(errno)); + write(ptys, ptyname, strlen(ptyname)); return(EX_OSERR); } - close(s[0]); - close(r[1]); + if (ptys > 2) + close(ptys); + /* exec telnet/ssh */ - if (execvp(argv[optind], argv + optind)) { - fprintf(stderr, "%s: execlp() failed: %s\n", progname, + execvp(argv[optind], argv + optind); + snprintf(ptyname, FILENAME_MAX, "%s: execvp() failed: %s\n", progname, + strerror(errno)); + write(ptys, ptyname, strlen(ptyname)); + return(EX_TEMPFAIL); + /*NOTREACHED*/ + } + + /* parent */ + if (debug) + fprintf(stderr, "child %d\n", child); + + signal(SIGHUP, (void *) sighdlr); + + /* close the slave pty */ + close(ptys); + + devnull = open("/dev/null", O_RDWR); + + /* make FDs non-blocking */ + if (fcntl(ptym, F_SETFL, O_NONBLOCK) || + fcntl(fileno(stdin), F_SETFL, O_NONBLOCK) || + fcntl(fileno(stdout), F_SETFL, O_NONBLOCK)) { + fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname, strerror(errno)); - return(EX_TEMPFAIL); + exit(EX_OSERR); + } + + /* loop to read on stdin and ptym */ +#define POLLEXP (POLLERR | POLLHUP | POLLNVAL) + pfds[0].fd = fileno(stdin); + pfds[0].events = POLLIN | POLLEXP; + pfds[1].fd = fileno(stdout); + pfds[2].fd = ptym; + pfds[2].events = POLLIN | POLLEXP; + + while (1) { + bytes = poll(pfds, 3, (timeo * 1000)); + if (bytes == 0) { + if (drain) + break; + /* timeout */ + continue; } - /* not reached */ - } else { - /* parent */ - if (debug) - fprintf(stderr, "child %d\n", child); - - /* close the child's side of the pipes; we write s[1], read r[0] */ - close(s[0]); - close(r[1]); - - /* make FDs non-blocking */ - if (fcntl(s[1], F_SETFL, O_NONBLOCK) || - fcntl(r[0], F_SETFL, O_NONBLOCK) || - fcntl(0, F_SETFL, O_NONBLOCK) || - fcntl(1, F_SETFL, O_NONBLOCK)) { - fprintf(stderr, "%s: fcntl(NONBLOCK) failed: %s\n", progname, - strerror(errno)); - exit(EX_OSERR); + if (bytes == -1) { + switch (errno) { + case EAGAIN: + case EINTR: + break; + default: + rval = EX_IOERR; + break; + } + continue; } - /* loop to read on stdin and r[0] */ - FD_ZERO(&rfds); FD_ZERO(&wfds); - hbufp = hbuf; tbufp = tbuf; + /* + * write buffers first + * write hbuf (stdin) -> ptym + */ + if ((pfds[2].revents & POLLOUT) && hlen) { + if ((bytes = write(pfds[2].fd, hbuf, hlen)) < 0 && + errno != EINTR && errno != EAGAIN) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); + hbuf[0] = '\0'; + hlen = 0; + drain = 1; + pfds[2].events &= ~POLLOUT; - while (1) { - FD_SET(0, &rfds); FD_SET(r[0], &rfds); - /* if we have stuff in our buffer(s), we select on writes too */ - FD_ZERO(&wfds); - if (hlen) { - FD_SET(s[1], &wfds); - } - if (tlen) { - FD_SET(1, &wfds); + break; + } else if (bytes > 0) { + strcpy(hbuf, hbuf + bytes); + hlen -= bytes; + if (hlen < 1) + pfds[2].events &= ~POLLOUT; } + } else if (pfds[2].revents & POLLEXP) { + hbuf[0] = '\0'; + hlen = 0; + pfds[2].events &= POLLIN; + break; + } - switch (select(r[1], &rfds, &wfds, NULL, &to)) { - case 0: - /* timeout */ - /* XXX what do i do here? */ + /* write tbuf -> stdout */ + if ((pfds[1].revents & POLLOUT) && tlen) { + /* + * if there is an escape char that didnt get filter()'d, + * we need to write only up to that point and wait for + * the bits that complete the escape sequence. if at least + * two bytes follow it, write it anyway as filter() didnt + * match it. + */ + bytes = tlen; + if ((tbufp = index(tbuf, 0x1b)) != NULL) + if (tlen - (tbufp - tbuf) < 2) + bytes = tbufp - tbuf; + + if ((bytes = write(pfds[1].fd, tbuf, bytes)) < 0 && + errno != EINTR && errno != EAGAIN) { + fprintf(stderr, "%s: write() failed: %s\n", progname, + strerror(errno)); break; - case -1: - switch (errno) { - case EINTR: /* interrupted syscall */ + tbuf[0] = '\0'; + tlen = 0; + drain = 1; + pfds[1].events = 0; + } else if (bytes > 0) { + strcpy(tbuf, tbuf + bytes); + tlen -= bytes; + if (tlen < 1) + pfds[1].events &= ~POLLOUT; + } + } else if (pfds[1].revents & POLLEXP) { + break; + tbuf[0] = '\0'; + tlen = 0; + pfds[1].fd = devnull; + pfds[1].events = 0; + } + + /* read stdin -> hbuf */ + if (pfds[0].revents & POLLIN) { + if (BUFSZ - hlen > 1) { + bytes = read(pfds[0].fd, hbuf + hlen, (BUFSZ - 1) - hlen); + if (bytes > 0) { + hlen += bytes; + hbuf[hlen] = '\0'; + pfds[2].events |= POLLOUT; + } else if (bytes == 0 && errno != EAGAIN && errno != EINTR) { break; - default: - exit(EX_IOERR); - } - break; - default: - /* check exceptions first */ - - /* which FD is ready? write our buffers asap. */ - /* write hbuf (stdin) -> s[1] */ - if (FD_ISSET(s[1], &wfds) && hlen) { - if ((hlen = write(s[1], hbuf, hlen)) < 0) { - fprintf(stderr, "%s: write() failed: %s\n", progname, - strerror(errno)); - close(s[1]); - } else - strcpy(hbuf, hbuf + hlen); - - hlen = strlen(hbuf); - } - /* write tbuf -> stdout */ - if (FD_ISSET(1, &wfds) && tlen) { - /* if there is an escape char that didnt get filter()'d, - * we need to only write up to that point and wait for - * the bits that complete the escape sequence - */ - if ((tbufp = index(tbuf, 0x1b)) != NULL) - tlen = tbufp - tbuf; - - if ((tlen = write(1, tbuf, tlen)) < 0) { - fprintf(stderr, "%s: write() failed: %s\n", progname, - strerror(errno)); - close(1); - } else - strcpy(tbuf, tbuf + tlen); - - tlen = strlen(tbuf); + /* EOF or read error */ + drain = 1; + pfds[0].fd = devnull; + pfds[0].events = 0; } - if (FD_ISSET(0, &rfds)) { - /* read stdin into hbuf */ - if (BUFSZ - hlen > 1) { - hlen += read(0, hbuf + hlen, (BUFSZ - 1) - hlen); - if (hlen > 0) { - hbuf[hlen] = '\0'; - } else if (hlen == 0 || errno != EAGAIN) - /* EOF or read error */ - close(0); - - hlen = strlen(hbuf); - } - } else if (FD_ISSET(r[0], &rfds)) { - /* read telnet/ssh into tbuf, then filter */ - if (BUFSZ - tlen > 1) { - tlen += read(r[0], tbuf + tlen, (BUFSZ - 1) - tlen); - if (tlen > 0) { - tbuf[tlen] = '\0'; - tlen = filter(tbuf, tlen); - } else if (tlen == 0 || errno != EAGAIN) - /* EOF or read error */ - close(r[0]); - - tlen = strlen(tbuf); - } - } - - break; } + } else if (pfds[0].revents & POLLEXP) { + break; + drain = 1; + pfds[0].fd = devnull; + pfds[0].events = 0; } - /* close */ - close(0); - close(1); - close(s[1]); - close(r[0]); + /* read telnet/ssh -> tbuf, then filter */ + if (pfds[2].revents & POLLIN) { + if (BUFSZ - tlen > 1) { + bytes = read(pfds[2].fd, tbuf + tlen, (BUFSZ - 1) - tlen); + if (bytes > 0) { + tlen += bytes; + tbuf[tlen] = '\0'; + tlen = filter(tbuf, tlen); + if (tlen > 0) + pfds[1].events |= POLLOUT; + } else if (bytes == 0 && errno != EAGAIN && errno != EINTR) { + /* EOF or read error */ + break; + drain = 1; + pfds[2].fd = devnull; + pfds[2].events = 0; + } + } + } else if (pfds[2].revents & POLLEXP) { + break; + drain = 1; + pfds[2].fd = devnull; + pfds[2].events = 0; + } + } + /* try to flush buffers */ + if (hlen) { + (void) write(pfds[2].fd, hbuf, hlen); + hlen = 0; + } + if (tlen) { + (void) write(pfds[1].fd, tbuf, tlen); + tlen = 0; + } + if ((bytes = read(pfds[2].fd, tbuf, (BUFSZ - 1))) > 0) { + tbuf[bytes] = '\0'; + tlen = filter(tbuf, bytes); + (void) write(pfds[1].fd, tbuf, tlen); } + tcdrain(pfds[1].fd); + if ((hlen = read(pfds[0].fd, hbuf, (BUFSZ - 1))) > 0) { + (void) write(pfds[2].fd, hbuf, hlen); + } + tcdrain(pfds[2].fd); - if (! kill(child, SIGQUIT)) + if (child && ! kill(child, SIGINT)) reapchild(); - return(EX_OK); + return(rval); } int @@ -291,7 +459,7 @@ filter(buf, len) int len; { static regmatch_t pmatch[1]; -#define N_REG 11 /* number of regexes in reg[][] */ +#define N_REG 13 /* number of regexes in reg[][] */ static regex_t preg[N_REG]; static char reg[N_REG][50] = { /* vt100/220 escape codes */ "\e7\e\\[1;24r\e8", /* ds */ @@ -307,8 +475,11 @@ filter(buf, len) "\e\\[\\?7l", /* RA */ "\e\\[\\?25h", /* ve */ "\e\\[\\?25l", /* vi */ + "\e\\[K", /* ce */ - "\eE", /* replace w/ CR */ + /* replace these with CR */ + "\e\\[0m", /* me */ + "\eE", }; char ebuf[256]; size_t nmatch = 1; @@ -319,7 +490,7 @@ filter(buf, len) if (index(buf, 0x1b) == 0 || len == 0) return(len); - for (x = 0; x < N_REG - 1; x++) { + for (x = 0; x < N_REG - 2; x++) { if (! init) { if ((err = regcomp(&preg[x], reg[x], REG_EXTENDED))) { regerror(err, &preg[x], ebuf, 256); @@ -342,27 +513,28 @@ filter(buf, len) /* replace \eE w/ CR NL */ if (! init++) { - if ((err = regcomp(&preg[N_REG - 1], reg[N_REG - 1], REG_EXTENDED))) { - regerror(err, &preg[N_REG - 1], ebuf, 256); - fprintf(stderr, "%s: regex compile failed: %s\n", progname, - ebuf); - abort(); - } + for (x = N_REG - 2; x < N_REG; x++) + if ((err = regcomp(&preg[x], reg[x], REG_EXTENDED))) { + regerror(err, &preg[x], ebuf, 256); + fprintf(stderr, "%s: regex compile failed: %s\n", progname, + ebuf); + abort(); + } } - while (1) - if ((err = regexec(&preg[N_REG - 1], buf, nmatch, pmatch, 0))) { + for (x = N_REG - 2; x < N_REG; x++) { + if ((err = regexec(&preg[x], buf, nmatch, pmatch, 0))) { if (err != REG_NOMATCH) { - regerror(err, &preg[N_REG - 1], ebuf, 256); + regerror(err, &preg[x], ebuf, 256); fprintf(stderr, "%s: regexec failed: %s\n", progname, ebuf); abort(); - } else - break; + } } else { - *(buf + pmatch[0].rm_so) = '\n'; - strcpy(buf + pmatch[0].rm_so + 1, buf + pmatch[0].rm_eo); - x = 0; + *(buf + pmatch[0].rm_so) = '\r'; + *(buf + pmatch[0].rm_so + 1) = '\n'; + strcpy(buf + pmatch[0].rm_so + 2, buf + pmatch[0].rm_eo); + x = N_REG - 2; } - + } return(strlen(buf)); } @@ -376,19 +548,54 @@ reapchild(void) while ((pid = wait3(&status, WNOHANG, 0)) > 0) if (debug) fprintf(stderr, "reap child %d\n", pid); + if (pid == child) + child = 0; - /*exit(1);*/ -return; + return; +} + +RETSIGTYPE +sighdlr(int sig) +{ + if (debug) + fprintf(stderr, "GOT SIGNAL %d\n", sig); + drain = 1; + return; +} - /* not reached */ +#if !HAVE_UNSETENV +int +unsetenv(const char *name) +{ + char **victim, + **end; + int len; + if (environ == NULL) + return(0); + len = strlen(name); + victim = environ; + while (*victim != NULL) { + if (strncmp(name, *victim, len) == 0 && victim[0][len] == '=') + break; + victim++; + } + if (*victim == NULL) + return(0); + end = victim + 1; + while (*end != NULL) + end++; + end--; + *victim = *end; + *end = NULL; + return(0); } +#endif void usage(void) { - fprintf(stderr, -"usage: %s [-hv] [] []\n", - progname); + fprintf(stderr, "usage: %s [-hv] [-t timeout] []" + " []\n", progname); return; } @@ -398,3 +605,104 @@ vers(void) fprintf(stderr, "%s: %s version %s\n", progname, package, version); return; } + + +#if !HAVE_OPENPTY +#include +#define TTY_LETTERS "pqrstuvwxyzPQRST" +#define TTY_OLD_SUFFIX "0123456789abcdef" +#define TTY_NEW_SUFFIX "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + +int +openpty(int *amaster, int *aslave, char *name, struct termios *term, + struct winsize *winp) +{ + static char line[] = "/dev/XtyXX"; + const char *cp1, *cp2, *cp, *linep; + int master, slave; + gid_t ttygid; + mode_t mode; + struct group *gr; + +#if HAVE_PTMX + if ((master = +#if HAVE_PTMX_BSD + open("/dev/ptmx_bsd", O_RDWR)) +#else + open("/dev/ptmx", O_RDWR)) +#endif + != -1) { + linep = ptsname(master); + grantpt(master); + unlockpt(master); + if ((slave = open(linep, O_RDWR)) < 0) { + slave = errno; + (void) close(master); + errno = slave; + return(-1); + } +#if HAVE_PTMX_OSF + { + char buf[10240]; + if (ioctl (slave, I_LOOK, buf) != 0) + if (ioctl (slave, I_PUSH, "ldterm")) { + close(slave); + close(master); + return(-1); + } + } +#elif HAVE_STROPTS_H + ioctl(slave, I_PUSH, "ptem"); + ioctl(slave, I_PUSH, "ldterm"); + ioctl(slave, I_PUSH, "ttcompat"); +#endif + goto gotit; + } + if (errno != ENOENT) + return(-1); +#endif + + if ((gr = getgrnam("tty")) != NULL) { + ttygid = gr->gr_gid; + mode = S_IRUSR|S_IWUSR|S_IWGRP; + } else { + ttygid = getgid(); + mode = S_IRUSR|S_IWUSR; + } + + for (cp1 = TTY_LETTERS; *cp1; cp1++) { + line[8] = *cp1; + for (cp = cp2 = TTY_OLD_SUFFIX TTY_NEW_SUFFIX; *cp2; cp2++) { + line[5] = 'p'; + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno != ENOENT) + continue; /* busy */ + if (cp2 - cp + 1 < sizeof(TTY_OLD_SUFFIX)) + return -1; /* out of ptys */ + else + break; /* out of ptys in this group */ + } + line[5] = 't'; + linep = line; + if (chown(line, getuid(), ttygid) == 0 && + chmod(line, mode) == 0 && + (slave = open(line, O_RDWR, 0)) != -1) { +gotit: + *amaster = master; + *aslave = slave; + if (name) + (void)strcpy(name, linep); + if (term) + (void)tcsetattr(slave, TCSAFLUSH, term); + if (winp) + (void)ioctl(slave, TIOCSWINSZ, winp); + return 0; + } + (void)close(master); + } + } + errno = ENOENT; /* out of ptys */ + return -1; +} +#endif -- cgit