/* * Copyright (c) 1995, 1996 Gunther Schadow. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "ptydrv.h" #include #include #include #include #include #include #include #include #include #include #include #include "trap.h" #ifdef hpux /* HPUX declares select in */ # include #endif /***************************************************************** * * Forward data from master to destination. * * Listen at the master side of the pty for any incoming data * or close and ioctl requests. Ioctl requests are currently * just syslog-ed and answered by an ENOTTY. A close request * ends this procedure. */ result fwddata(int mfd, int pfd) { #ifdef hpux int nfds; fd_set rdfds, ecfds; struct request_info rqinf; #endif bool close_request = FALSE; char buf[BUF_SIZE+1]; int cnt; size_t total = 0; atsignal(SIGPIPE, 0) { syslog(LOG_ERR, "lost connection to destination"); goto fail; } do { #ifdef hpux /* * Listen at the master side of the pty for any incoming data * or close requests */ syslog(LOG_INFO, "waiting for data at pty ..."); FD_ZERO(&ecfds); FD_ZERO(&rdfds); FD_SET(mfd, &rdfds); FD_SET(mfd, &ecfds); select_again: nfds = select(FD_SETSIZE, &rdfds, NULL, &ecfds, NULL); if (nfds < 0) { if (errno == EINTR) goto select_again; else { syslog(LOG_ERR, __FUNCTION__ ":select: %m"); goto fail; } } /* * I just don't know exactly how to handle the condition when * select returns 0. Simply issue a warning and fail. */ if (nfds == 0) { syslog(LOG_WARNING, __FUNCTION__ ":select: timeout or interrupt"); return 0; } /* * Select returned with either an open/close/ioctl request or * data to read. At this time we will only accept close and * requests and data (of course). */ if(FD_ISSET(mfd, &ecfds)) { DBG(syslog(LOG_DEBUG, "request trapped")); if (ioctl(mfd, TIOCREQCHECK, &rqinf) == FAIL) { if(errno == EINVAL) { syslog(LOG_WARNING, __FUNCTION__ ":TIOCREQCHECK: client died"); close_request = TRUE; } else { syslog(LOG_ERR, __FUNCTION__ ":TIOCREQCHECK: %m"); goto fail; } } else { int arg_buf[128]; if(rqinf.request == TIOCCLOSE) { DBG(syslog(LOG_DEBUG, "close request")); close_request = TRUE; } else { DBG(syslog(LOG_DEBUG, "handle ioctl request:")); logioctl(LOG_INFO, "ioctl:" , rqinf.request); if(rqinf.argget != 0) { if(ioctl(mfd, rqinf.argget, arg_buf) == FAIL) { syslog(LOG_ERR, "TIOCARGGET: %m"); goto fail; } if(istermios(rqinf.request)) logtermios(LOG_DEBUG, "termios:", (struct termios *)arg_buf); } tioctty(mfd, 1); rqinf.return_value = ioctl(mfd, rqinf.request, arg_buf); if(rqinf.return_value == FAIL) { rqinf.errno_error = errno; syslog(LOG_ERR, "ioctl failed: " "%d %m", rqinf.return_value); } else { DBG(syslog(LOG_DEBUG,"ioctl succeeded")); rqinf.errno_error = 0; } tioctty(mfd, 0); if(rqinf.argset != 0) { if(ioctl(mfd, rqinf.argset, arg_buf) == FAIL) { syslog(LOG_ERR, "TIOCARGSET: %m"); goto fail; } if(istermios(rqinf.request)) logtermios(LOG_DEBUG, "termios:", (struct termios *)arg_buf); } DBG(syslog(LOG_DEBUG, "ioctl request successful:")); } if (ioctl(mfd, TIOCREQSET, &rqinf) == FAIL) if(errno == EINVAL) { syslog(LOG_WARNING, __FUNCTION__ ":TIOCREQSET: client died"); close_request = TRUE; } else { syslog(LOG_ERR, __FUNCTION__ ":TIOREQSET: %m"); goto fail; } } } if(FD_ISSET(mfd, &rdfds)) { #endif /* hpux */ DBG(syslog(LOG_DEBUG, "reading from pty")); cnt = read(mfd, buf, BUF_SIZE); if (cnt < 0) /* error */ { syslog(LOG_ERR, __FUNCTION__ ":read: %m"); goto fail; } else if (cnt > 0 && pfd != FAIL) /* normal data */ { u_int ncnt, wcnt = cnt, start = 0; DBG(syslog(LOG_DEBUG, "writing %d bytes", cnt)); do { ncnt = write(pfd, &buf[start], wcnt); TSR(&buf[start], wcnt); if (ncnt < 1) { syslog(LOG_ERR, __FUNCTION__ "write: %m"); goto fail; } wcnt -= ncnt; start += ncnt; total += ncnt; } while(wcnt > 0); } else if (cnt == 0) { syslog(LOG_INFO, __FUNCTION__ ":read: returned 0"); #ifndef hpux close_request = TRUE; #endif } #ifdef hpux } #endif } while (!close_request); syslog(LOG_INFO, "%lu bytes transfered", total); return SUCCESS; fail: syslog(LOG_INFO, "%lu bytes transfered", total); return FAIL; }