+
+ nibuf = nobuf = 0;
+ ibufp = obufp = NULL;
+ pty_readable = stdin_readable = 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) {
+ FD_ZERO(&ready);
+ FD_ZERO(&writey);
+ if (nibuf != 0)
+ FD_SET(pty_master, &writey);
+ else if (stdin_readable)
+ FD_SET(ifd, &ready);
+ if (nobuf != 0)
+ FD_SET(ofd, &writey);
+ else if (pty_readable)
+ FD_SET(pty_master, &ready);
+ if (select(nfds, &ready, &writey, NULL, NULL) < 0) {
+ if (errno != EINTR)
+ fatal("select");
+ continue;
+ }
+ 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 = write(ofd, obufp, nobuf);
+ if (n < 0) {
+ if (errno != EIO) {
+ error("Error writing standard output: %m");
+ break;
+ }
+ pty_readable = 0;
+ nobuf = 0;
+ } else {
+ obufp += n;
+ nobuf -= n;
+ }
+ }
+ if (FD_ISSET(pty_master, &writey)) {
+ n = write(pty_master, ibufp, nibuf);
+ if (n < 0) {
+ if (errno != EIO) {
+ error("Error writing pseudo-tty master: %m");
+ break;
+ }
+ stdin_readable = 0;
+ nibuf = 0;
+ } else {
+ ibufp += n;
+ nibuf -= n;
+ }
+ }
+ }
+ exit(0);