- charshunt_pid = 0;
-}
-
-/*
- * charshunt - the character shunt, which passes characters between
- * the pty master side and the serial port (or stdin/stdout).
- * This runs as the user (not as root).
- * (We assume ofd >= ifd which is true the way this gets called. :-).
- */
-static void
-charshunt(ifd, ofd, record_file)
- int ifd, ofd;
- char *record_file;
-{
- int n, nfds;
- fd_set ready, writey;
- u_char *ibufp, *obufp;
- int nibuf, nobuf;
- int flags;
- int pty_readable, stdin_readable;
- struct timeval lasttime;
- FILE *recordf = NULL;
- int ilevel, olevel, max_level;
- struct timeval levelt, tout, *top;
-
- /*
- * Reset signal handlers.
- */
- signal(SIGHUP, SIG_IGN); /* Hangup */
- signal(SIGINT, SIG_DFL); /* Interrupt */
- signal(SIGTERM, SIG_DFL); /* Terminate */
- signal(SIGCHLD, SIG_DFL);
- signal(SIGUSR1, SIG_DFL);
- signal(SIGUSR2, SIG_DFL);
- signal(SIGABRT, SIG_DFL);
- signal(SIGALRM, SIG_DFL);
- signal(SIGFPE, SIG_DFL);
- signal(SIGILL, SIG_DFL);
- signal(SIGPIPE, SIG_DFL);
- signal(SIGQUIT, SIG_DFL);
- signal(SIGSEGV, SIG_DFL);
-#ifdef SIGBUS
- signal(SIGBUS, SIG_DFL);
-#endif
-#ifdef SIGEMT
- signal(SIGEMT, SIG_DFL);
-#endif
-#ifdef SIGPOLL
- signal(SIGPOLL, SIG_DFL);
-#endif
-#ifdef SIGPROF
- signal(SIGPROF, SIG_DFL);
-#endif
-#ifdef SIGSYS
- signal(SIGSYS, SIG_DFL);
-#endif
-#ifdef SIGTRAP
- signal(SIGTRAP, SIG_DFL);
-#endif
-#ifdef SIGVTALRM
- signal(SIGVTALRM, SIG_DFL);
-#endif
-#ifdef SIGXCPU
- signal(SIGXCPU, SIG_DFL);
-#endif
-#ifdef SIGXFSZ
- signal(SIGXFSZ, SIG_DFL);
-#endif
-
- /*
- * Open the record file if required.
- */
- if (record_file != NULL) {
- recordf = fopen(record_file, "a");
- if (recordf == NULL)
- error("Couldn't create record file %s: %m", record_file);
- }
-
- /* set all the fds to non-blocking mode */
- flags = fcntl(pty_master, F_GETFL);
- if (flags == -1
- || fcntl(pty_master, F_SETFL, flags | O_NONBLOCK) == -1)
- warn("couldn't set pty master to nonblock: %m");
- flags = fcntl(ifd, F_GETFL);
- if (flags == -1
- || fcntl(ifd, F_SETFL, flags | O_NONBLOCK) == -1)
- warn("couldn't set %s to nonblock: %m", (ifd==0? "stdin": "tty"));
- if (ofd != ifd) {
- flags = fcntl(ofd, F_GETFL);
- if (flags == -1
- || fcntl(ofd, F_SETFL, flags | O_NONBLOCK) == -1)
- warn("couldn't set stdout to nonblock: %m");
- }
-
- nibuf = nobuf = 0;
- ibufp = obufp = NULL;
- pty_readable = stdin_readable = 1;
-
- ilevel = olevel = 0;
- gettimeofday(&levelt, NULL);
- if (max_data_rate) {
- max_level = max_data_rate / 10;
- if (max_level < 100)
- max_level = 100;
- } else
- max_level = sizeof(inpacket_buf) + 1;
-
- nfds = (ofd > pty_master? ofd: pty_master) + 1;
- if (recordf != NULL) {
- gettimeofday(&lasttime, NULL);
- putc(7, recordf); /* put start marker */
- putc(lasttime.tv_sec >> 24, recordf);
- putc(lasttime.tv_sec >> 16, recordf);
- putc(lasttime.tv_sec >> 8, recordf);
- putc(lasttime.tv_sec, recordf);
- lasttime.tv_usec = 0;
- }
-
- while (nibuf != 0 || nobuf != 0 || pty_readable || stdin_readable) {
- top = 0;
- tout.tv_sec = 0;
- tout.tv_usec = 10000;
- FD_ZERO(&ready);
- FD_ZERO(&writey);
- if (nibuf != 0) {
- if (ilevel >= max_level)
- top = &tout;
- else
- FD_SET(pty_master, &writey);
- } else if (stdin_readable)
- FD_SET(ifd, &ready);
- if (nobuf != 0) {
- if (olevel >= max_level)
- top = &tout;
- else
- FD_SET(ofd, &writey);
- } else if (pty_readable)
- FD_SET(pty_master, &ready);
- if (select(nfds, &ready, &writey, NULL, top) < 0) {
- if (errno != EINTR)
- fatal("select");
- continue;
- }
- if (max_data_rate) {
- double dt;
- int nbt;
- struct timeval now;
-
- gettimeofday(&now, NULL);
- dt = (now.tv_sec - levelt.tv_sec
- + (now.tv_usec - levelt.tv_usec) / 1e6);
- nbt = (int)(dt * max_data_rate);
- ilevel = (nbt < 0 || nbt > ilevel)? 0: ilevel - nbt;
- olevel = (nbt < 0 || nbt > olevel)? 0: olevel - nbt;
- levelt = now;
- } else
- ilevel = olevel = 0;
- if (FD_ISSET(ifd, &ready)) {
- ibufp = inpacket_buf;
- nibuf = read(ifd, ibufp, sizeof(inpacket_buf));
- if (nibuf < 0 && errno == EIO)
- nibuf = 0;
- if (nibuf < 0) {
- if (!(errno == EINTR || errno == EAGAIN)) {
- error("Error reading standard input: %m");
- break;
- }
- nibuf = 0;
- } else if (nibuf == 0) {
- /* end of file from stdin */
- stdin_readable = 0;
- /* do a 0-length write, hopefully this will generate
- an EOF (hangup) on the slave side. */
- write(pty_master, inpacket_buf, 0);
- if (recordf)
- if (!record_write(recordf, 4, NULL, 0, &lasttime))
- recordf = NULL;
- } else {
- FD_SET(pty_master, &writey);
- if (recordf)
- if (!record_write(recordf, 2, ibufp, nibuf, &lasttime))
- recordf = NULL;
- }
- }
- if (FD_ISSET(pty_master, &ready)) {
- obufp = outpacket_buf;
- nobuf = read(pty_master, obufp, sizeof(outpacket_buf));
- if (nobuf < 0 && errno == EIO)
- nobuf = 0;
- if (nobuf < 0) {
- if (!(errno == EINTR || errno == EAGAIN)) {
- error("Error reading pseudo-tty master: %m");
- break;
- }
- nobuf = 0;
- } else if (nobuf == 0) {
- /* end of file from the pty - slave side has closed */
- pty_readable = 0;
- stdin_readable = 0; /* pty is not writable now */
- nibuf = 0;
- close(ofd);
- if (recordf)
- if (!record_write(recordf, 3, NULL, 0, &lasttime))
- recordf = NULL;
- } else {
- FD_SET(ofd, &writey);
- if (recordf)
- if (!record_write(recordf, 1, obufp, nobuf, &lasttime))
- recordf = NULL;
- }
- }
- if (FD_ISSET(ofd, &writey)) {
- n = nobuf;
- if (olevel + n > max_level)
- n = max_level - olevel;
- n = write(ofd, obufp, n);
- if (n < 0) {
- if (errno != EIO) {
- error("Error writing standard output: %m");
- break;
- }
- pty_readable = 0;
- nobuf = 0;
- } else {
- obufp += n;
- nobuf -= n;
- olevel += n;
- }
- }
- if (FD_ISSET(pty_master, &writey)) {
- n = nibuf;
- if (ilevel + n > max_level)
- n = max_level - ilevel;
- n = write(pty_master, ibufp, n);
- if (n < 0) {
- if (errno != EIO) {
- error("Error writing pseudo-tty master: %m");
- break;
- }
- stdin_readable = 0;
- nibuf = 0;
- } else {
- ibufp += n;
- nibuf -= n;
- ilevel += n;
- }
- }
- }
- exit(0);
-}