diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2015-07-08 20:46:52 -0400 |
commit | fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4 (patch) | |
tree | bdda434976bc09c864f2e4fa6f16ba1952b1e555 /unix/os/zfiotx.c | |
download | iraf-linux-fa080de7afc95aa1c19a6e6fc0e0708ced2eadc4.tar.gz |
Initial commit
Diffstat (limited to 'unix/os/zfiotx.c')
-rw-r--r-- | unix/os/zfiotx.c | 991 |
1 files changed, 991 insertions, 0 deletions
diff --git a/unix/os/zfiotx.c b/unix/os/zfiotx.c new file mode 100644 index 00000000..e387dfaa --- /dev/null +++ b/unix/os/zfiotx.c @@ -0,0 +1,991 @@ +/* Copyright(c) 1986 Association of Universities for Research in Astronomy Inc. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/stat.h> +#include <signal.h> +#include <setjmp.h> +#include <stdio.h> +#include <errno.h> + +#ifdef LINUX +#define USE_SIGACTION +#endif + +#ifdef SYSV +#include <termios.h> +#else +#include <sgtty.h> +#endif + +#ifndef O_NDELAY +#include <fcntl.h> +#endif + +#define import_kernel +#define import_knames +#define import_zfstat +#define import_spp +#include <iraf.h> + +/* + * ZFIOTX -- File i/o to textfiles, for UNIX 4.1BSD. This driver is used for + * both terminals and ordinary disk text files. I/O is via the C library + * stdio routines, which provide buffering. + * + * On input, we must check for newline and terminate when it has been read, + * including the newline character in the return buffer and in the character + * count. If the buffer limit is reached before newline is found, we return + * the line without a newline, and return the rest of the line in the next + * read request. If a single character is requested character mode is + * asserted, i.e., if the device is a terminal RAW is enabled and ECHO and + * CRMOD (CR to LF mapping) are disabled. A subsequent request to read or + * write more than one character restores line mode. + * + * On output, we transmit the specified number of characters, period. + * No checking for newline or EOS is performed. Text may contain null + * characters (note that EOS == NUL). There is no guarantee that the + * output line will contain a newline. When flushing partial lines to a + * terminal, this is often not the case. When FIO writes a very long + * line and the FIO buffer overflows, it will flush a partial line, + * passing the rest of the line (with newline delimiter) in the next + * write request. The newline should be included in the data as stored + * on disk, if possible. It is not necessary to map newlines upon output + * because UNIX does this already. + * + * N.B.: An SPP char is usually not a byte, so these routines usually + * perform type conversion. The actual SPP datatype is defined in language.h + * An SPP char is a signed integer, but only values in the range 0-127 may + * be written to a text file. We assume that character set conversion (e.g., + * ASCII to EBCDIC) is not necessary since all 4.1BSD hosts we are aware of + * are ASCII machines. + */ + +#define MAXOTTYS 20 /* max simultaneous open ttys */ +#define MAX_TRYS 2 /* max interrupted trys to read */ +#define NEWLINE '\n' + +/* The ttyport descriptor is used by the tty driver (zfiotx). */ +struct ttyport { + int inuse; /* port in use */ + int chan; /* host channel (file descrip.) */ + unsigned device; /* tty device number */ + int flags; /* port flags */ + char redraw; /* redraw char, sent after susp */ +#ifdef SYSV + struct termios tc; /* normal tty state */ + struct termios save_tc; /* saved rawmode tty state */ +#else + struct sgttyb tc; /* normal tty state */ + struct sgttyb save_tc; /* saved rawmode tty state */ +#endif +}; + + + +#define CTRLC 3 +extern int errno; +static jmp_buf jmpbuf; +static int tty_getraw = 0; /* raw getc in progress */ +#ifdef USE_SIGACTION +static struct sigaction sigint, sigterm; +static struct sigaction sigtstp, sigcont; +static struct sigaction oldact; +#else +static SIGFUNC sigint, sigterm; +static SIGFUNC sigtstp, sigcont; +#endif +static void tty_rawon(), tty_reset(), uio_bwrite(); +static void tty_onsig(), tty_stop(), tty_continue(); + +/* The ttyports array describes up to MAXOTTYS open terminal i/o ports. + * Very few processes will ever have more than one or two ports open at + * one time. ttyport descriptors are allocated one per tty device, using + * the minor device number to identify the device. This serves to + * uniquely identify each tty device regardless of the file descriptor + * used to access it. Multiple file descriptors (e.g. stdin, stdout, + * stderr) used to access a single device must use description of the + * device state. + */ +struct ttyport ttyports[MAXOTTYS]; +struct ttyport *lastdev = NULL; + +/* Omit this for now; it was put in for an old Linux libc bug, and since libc + * is completely different now the need for it has probably gone away. + * + * #ifdef LINUX + * #define FCANCEL + * #endif + */ +#ifdef FCANCEL +/* The following definition has intimate knowledge of the STDIO structures. */ +#define fcancel(fp) ( \ + (fp)->_IO_read_ptr = (fp)->_IO_read_end = (fp)->_IO_read_base,\ + (fp)->_IO_write_ptr = (fp)->_IO_write_end = (fp)->_IO_write_base) +#endif + + +/* ZOPNTX -- Open or create a text file. The pseudo-files "unix-stdin", + * "unix-stdout", and "unix-stderr" are treated specially. These denote the + * UNIX stdio streams of the process. These streams are not really opened + * by this driver, but ZOPNTX should be called on these streams to + * properly initialize the file descriptor. + */ +int +ZOPNTX ( + PKCHAR *osfn, /* UNIX filename */ + XINT *mode, /* file access mode */ + XINT *chan /* UNIX channel of file (output) */ +) +{ + register int fd; + register FILE *fp; + struct stat filestat; + int newmode, maskval; + FILE *fopen(); + char *fmode; + + /* Map FIO access mode into UNIX/stdio access mode. + */ + switch (*mode) { + case READ_ONLY: + fmode = "r"; + break; + case READ_WRITE: + fmode = "r+"; /* might not work on old systems */ + break; + case APPEND: + fmode = "a"; + break; + case WRITE_ONLY: + fmode = "w"; + break; + case NEW_FILE: /* create for appending */ + fmode = "w"; + break; + default: + goto error; + } + + /* Open or create file. If a new file is created it is necessary + * to explicitly set the file access permissions as indicated by + * FILE_MODEBITS in kernel.h. This is done in such a way that the + * user's UMASK bits are preserved. + */ + if (strcmp ((char *)osfn, U_STDIN) == 0) { + fp = stdin; + } else if (strcmp ((char *)osfn, U_STDOUT) == 0) { + fp = stdout; + } else if (strcmp ((char *)osfn, U_STDERR) == 0) { + fp = stderr; + } else if ((fp = fopen ((char *)osfn, fmode)) == NULL) + goto error; + + fd = fileno (fp); + if (fstat (fd, &filestat) == ERR) { + if (fd > 2) + fclose (fp); + goto error; + } else if (fd >= MAXOFILES) { + if (fd > 2) + fclose (fp); + goto error; + } + + /* If regular file apply the umask. */ + if (fd > 2 && S_ISREG(filestat.st_mode) && + (*mode == WRITE_ONLY || *mode == NEW_FILE)) { + umask (maskval = umask (022)); + newmode = ((filestat.st_mode | 066) & ~maskval); + (void) chmod ((char *)osfn, newmode); + } + + /* Set up kernel file descriptor. + */ + zfd[fd].fp = fp; + zfd[fd].fpos = 0; + zfd[fd].nbytes = 0; + zfd[fd].io_flags = 0; + zfd[fd].port = (char *) NULL; + + zfd[fd].flags = (KF_NOSEEK | KF_NOSTTY); + if (S_ISREG (filestat.st_mode)) + zfd[fd].flags &= ~KF_NOSEEK; + if (S_ISCHR (filestat.st_mode)) + zfd[fd].flags &= ~KF_NOSTTY; + + /* If we are opening a terminal device set up ttyport descriptor. */ + if (!(zfd[fd].flags & KF_NOSTTY)) { + register struct ttyport *port; + register unsigned device; + register int i; + + /* Check if we already have a descriptor for this device. */ + device = (filestat.st_dev << 16) + filestat.st_rdev; + for (i=0, port = &ttyports[0]; i < MAXOTTYS; i++, port++) + if (port->inuse && port->device == device) { + zfd[fd].port = (char *) port; + port->inuse++; + goto done; + } + + /* Fill in a fresh descriptor. */ + port = &ttyports[0]; + for (i=MAXOTTYS; --i >= 0 && port->inuse; port++) + ; + if (i >= MAXOTTYS) + goto error; + + port->chan = fd; + port->device = device; + port->flags = 0; + port->redraw = 0; + port->inuse = 1; + + zfd[fd].port = (char *) port; + } + +done: + *chan = fd; + return (*chan); + +error: + *chan = XERR; + return (*chan); +} + + +/* ZCLSTX -- Close a text file. + */ +int +ZCLSTX (XINT *fd, XINT *status) +{ + register struct fiodes *kfp = &zfd[*fd]; + register struct ttyport *port = (struct ttyport *) kfp->port; + + /* Disable character mode if still in effect. If this is necessary + * then we have already saved the old tty status flags in sg_flags. + */ + if (port && (port->flags & KF_CHARMODE)) + tty_reset (port); + + /* Close the file. Set file pointer field of kernel file descriptor + * to null to indicate that the file is closed. + * + * [NOTE] -- fclose errors are ignored if we are closing a terminal + * device. This was necessary on the Suns and it was not clear why + * a close error was occuring (errno was EPERM - not owner). + */ + *status = (fclose(kfp->fp) == EOF && kfp->flags&KF_NOSTTY) ? XERR : XOK; + + kfp->fp = NULL; + if (port) { + kfp->port = NULL; + if (--port->inuse < 0) + port->inuse = 0; + if (lastdev == port) + lastdev = NULL; + } + + return (*status); +} + + +/* ZFLSTX -- Flush any buffered textual output. + */ +int +ZFLSTX (XINT *fd, XINT *status) +{ + *status = (fflush (zfd[*fd].fp) == EOF) ? XERR : XOK; + return ((int) *status); +} + + +/* ZGETTX -- Get a line of text from a text file. Unpack machine chars + * into type XCHAR. If output buffer is filled before newline is encountered, + * the remainder of the line will be returned in the next call, and the + * current line will NOT be newline terminated. If maxchar==1 assert + * character mode, otherwise assert line mode. + */ +int +ZGETTX (XINT *fd, XCHAR *buf, XINT *maxchars, XINT *status) +{ + register FILE *fp; + register XCHAR *op; + register int ch, maxch = *maxchars; + register struct fiodes *kfp; + struct ttyport *port; + int nbytes, ntrys; + + if (maxch <= 0) { + *status = 0; + return (*status); + } + + kfp = &zfd[*fd]; + port = (struct ttyport *) kfp->port; + fp = kfp->fp; + + /* If maxch=1 assert char mode if legal on device, otherwise clear + * char mode if set. Ignore ioctl errors if ioctl is illegal on + * device. + */ + if (port) { + if (maxch == 1 && !(port->flags & KF_CHARMODE)) + tty_rawon (port, 0); + else if (maxch > 1 && (port->flags & KF_CHARMODE)) { + /* Disable character mode. If this is necessary then we have + * already saved the old tty status flags in sg_flags. + */ + tty_reset (port); + } + } + + /* Copy the next line of text into the user buffer. Keep track of + * file offsets of current line and next line for ZNOTTX. A call to + * ZNOTTX will return the value of kfp->fpos, the file offset of the + * next line to be read (unless newline has not yet been seen on the + * current line due to a partial read). The following while loop is + * the inner loop of text file input, hence is heavily optimized at + * the expense of some clarity. If the host is non-ASCII add a lookup + * table reference to this loop to map chars from the host character + * set to ASCII. + * + * N.B.: If an interrupt occurs during the read and the output buffer + * is still empty, try to complete the read. This can happen when + * an interrupt occurs while waiting for input from the terminal, in + * which case recovery is probably safe. + */ + if (!port || !(port->flags & KF_CHARMODE)) { + /* Read in line mode. + */ + ntrys = MAX_TRYS; + do { + clearerr (fp); + op = buf; + errno = 0; + while (*op++ = ch = getc(fp), ch != EOF) { + if (--maxch <= 0 || ch == NEWLINE) + break; + } +#ifdef FCANCEL + if (errno == EINTR) + fcancel (fp); +#endif + } while (errno == EINTR && op-1 == buf && --ntrys >= 0); + + *op = XEOS; + nbytes = *maxchars - maxch; + + } else if (kfp->flags & KF_NDELAY) { + /* Read a single character in nonblocking raw mode. Zero + * bytes are returned if there is no data to be read. + */ + struct timeval timeout; + int chan = fileno(fp); + fd_set rfds; + char data[1]; + + FD_ZERO (&rfds); + FD_SET (chan, &rfds); + timeout.tv_sec = 0; + timeout.tv_usec = 0; + clearerr (fp); + + if (select (chan+1, &rfds, NULL, NULL, &timeout)) { + if (read (chan, data, 1) != 1) { + *status = XERR; + return (XERR); + } + ch = *data; + goto outch; + } else { + *buf = XEOS; + *status = 0; + return (*status); + } + + } else { + /* Read a single character in raw mode. Catch interrupts and + * return the interrupt character as an ordinary character. + * We map interrupts in this way, rather than use raw mode + * (which disables interrupts and all other input processing) + * because ctrl/s ctrl/q is disabled in raw mode, and that can + * cause sporadic protocol failures. + */ +#ifdef USE_SIGACTION + sigint.sa_handler = (SIGFUNC) tty_onsig; + sigemptyset (&sigint.sa_mask); + sigint.sa_flags = SA_NODEFER; + sigaction (SIGINT, &sigint, &oldact); + + sigterm.sa_handler = (SIGFUNC) tty_onsig; + sigemptyset (&sigterm.sa_mask); + sigterm.sa_flags = SA_NODEFER; + sigaction (SIGTERM, &sigterm, &oldact); +#else + sigint = (SIGFUNC) signal (SIGINT, (SIGFUNC)tty_onsig); + sigterm = (SIGFUNC) signal (SIGTERM, (SIGFUNC)tty_onsig); +#endif + tty_getraw = 1; + + /* Async mode can be cleared by other processes (e.g. wall), + * so reset it on every nonblocking read. This code should + * never be executed as KF_NDELAY is handled specially above, + * but it does no harm to leave it in here anyway. + */ + if (kfp->flags & KF_NDELAY) + fcntl (*fd, F_SETFL, kfp->io_flags | O_NDELAY); + + if ((ch = setjmp (jmpbuf)) == 0) { + clearerr (fp); + ch = getc (fp); + } +#ifdef FCANCEL + if (ch == CTRLC) + fcancel (fp); +#endif + +#ifdef USE_SIGACTION + sigaction (SIGINT, &oldact, NULL); + sigaction (SIGTERM, &oldact, NULL); +#else + signal (SIGINT, sigint); + signal (SIGTERM, sigterm); +#endif + tty_getraw = 0; + + /* Clear parity bit just in case raw mode is used. + */ +outch: op = buf; + if (ch == EOF) { + *op++ = ch; + nbytes = 0; + } else { + *op++ = (ch & 0177); + nbytes = 1; + } + *op = XEOS; + } + + /* Check for errors and update offsets. If the last char copied + * was EOF step on it with an EOS. In nonblocking raw mode EOF is + * indistinguishable from a no-data read, but it doesn't matter + * especially since a ctrl/d, ctrl/z, etc. typed by the user is + * passed through as data. + */ + if (ferror (fp)) { + clearerr (fp); + *op = XEOS; + nbytes = (kfp->flags&KF_NDELAY && errno==EWOULDBLOCK) ? 0 : XERR; + } else { + kfp->nbytes += nbytes; + switch (*--op) { + case NEWLINE: + kfp->fpos += kfp->nbytes; + kfp->nbytes = 0; + break; + case EOF: + *op = XEOS; + break; + } + } + + *status = nbytes; + + return (*status); +} + + +/* ZNOTTX -- Return the seek offset of the beginning of the current line + * of text (file offset of char following last newline seen). + */ +int +ZNOTTX (XINT *fd, XLONG *offset) +{ + *offset = zfd[*fd].fpos; + return ((int) *offset); +} + + +/* ZPUTTX -- Put "nchars" characters into the text file "fd". The final + * character will always be a newline, unless the FIO line buffer overflowed, + * in which case the correct thing to do is to write out the line without + * artificially adding a newline. We do not check for newlines in the text, + * hence ZNOTTX will return the offset of the next write, which will be the + * offset of the beginning of a line of text only if we are called to write + * full lines of text. + */ +int +ZPUTTX ( + XINT *fd, /* file to be written to */ + XCHAR *buf, /* data to be output */ + XINT *nchars, /* nchars to write to file */ + XINT *status /* return status */ +) +{ + register FILE *fp; + register int nbytes; + register struct fiodes *kfp = &zfd[*fd]; + struct ttyport *port; + int count, ch; + XCHAR *ip; + char *cp; + + count = nbytes = *nchars; + port = (struct ttyport *) kfp->port; + fp = kfp->fp; + + /* Clear raw mode if raw mode is set, the output file is a tty, and + * more than one character is being written. We must get an exact + * match to the RAWOFF string for the string to be recognized. + * The string is recognized and removed whether or not raw mode is + * in effect. The RAWON sequence may also be issued to turn raw + * mode on. The SETREDRAW sequence is used to permit an automatic + * screen redraw when a suspended process receives SIGCONT. + */ + if ((*buf == '\033' && count == LEN_RAWCMD) || count == LEN_SETREDRAW) { + /* Note that we cannot use strcmp since buf is XCHAR. */ + + /* The disable rawmode sequence. */ + for (ip=buf, cp=RAWOFF; *cp && (*ip == *cp); ip++, cp++) + ; + if (*cp == EOS) { + tty_reset (port); + *status = XOK; + return (XOK); + } + + /* The enable rawmode sequence. The control sequence is followed + * by a single modifier character, `D' denoting a normal blocking + * character read, and `N' nonblocking character reads. + */ + for (ip=buf, cp=RAWON; *cp && (*ip == *cp); ip++, cp++) + ; + if (*cp == EOS) { + tty_rawon (port, (*ip++ == 'N') ? KF_NDELAY : 0); + *status = XOK; + return (XOK); + } + + /* The set-redraw control sequence. If the redraw code is + * set to a nonnull value, that value will be returned to the + * reader in the next GETC call following a process + * suspend/continue, as if the code had been typed by the user. + */ + for (ip=buf, cp=SETREDRAW; *cp && (*ip == *cp); ip++, cp++) + ; + if (*cp == EOS) { + if (port) + port->redraw = *ip; + *status = XOK; + return (XOK); + } + } + + /* Do not check for EOS; merely output the number of characters + * requested. Checking for EOS prevents output of nulls, used for + * padding to create delays on terminals. We must pass all legal + * ASCII chars, i.e., all chars in the range 0-127. The results of + * storing non-ASCII chars in a text file are system dependent. + * If the host is not ASCII then a lookup table reference should be + * added to this loop to map ASCII chars to the host character set. + * + * The uio_bwrite function moves the characters in a block and is + * more efficient than character at a time output with putc, if the + * amount of text to be moved is large. + */ + if (nbytes < 10) { + for (ip=buf; --nbytes >= 0; ) { + ch = *ip++; + putc (ch, fp); + } + } else + uio_bwrite (fp, buf, nbytes); + + kfp->fpos += count; + + /* If an error occurred while writing to the file, clear the error + * on the host stream and report a file write error to the caller. + * Ignore the special case of an EBADF occuring while writing to the + * terminal, which occurs when a background job writes to the terminal + * after the user has logged out. + */ + if (ferror (fp)) { + clearerr (fp); + if (errno == EBADF && (fp == stdout || fp == stderr)) + *status = count; + else + *status = XERR; + } else + *status = count; + + return (*status); +} + + +/* ZSEKTX -- Seek on a text file to the character offset given by a prior + * call to ZNOTTX. This offset should always refer to the beginning of a line. + */ +int +ZSEKTX (XINT *fd, XLONG *znottx_offset, XINT *status) +{ + register struct fiodes *kfp = &zfd[*fd]; + + /* Clear the byte counter, used to keep track of offsets within + * a line of text when reading sequentially. + */ + kfp->nbytes = 0; + + /* Ignore seeks to the beginning or end of file on special devices + * (pipes or terminals). A more specific seek on such a device + * is an error. + */ + if (kfp->flags & KF_NOSEEK) { + /* Seeks are illegal on this device. Seeks to BOF or EOF are + * permitted but are ignored. + */ + switch (*znottx_offset) { + case XBOF: + case XEOF: + kfp->fpos = 0; + break; + default: + kfp->fpos = ERR; + } + } else { + /* Seeks are permitted on this device. The seek offset is BOF, + * EOF, or a value returned by ZNOTTX. + */ + switch (*znottx_offset) { + case XBOF: + kfp->fpos = fseek (kfp->fp, 0L, 0); + break; + case XEOF: + kfp->fpos = fseek (kfp->fp, 0L, 2); + break; + default: + kfp->fpos = fseek (kfp->fp, *znottx_offset, 0); + } + } + + if (kfp->fpos == ERR) { + *status = XERR; + } else if (kfp->flags & KF_NOSEEK) { + kfp->fpos = 0; + *status = XOK; + } else { + kfp->fpos = ftell (kfp->fp); + *status = XOK; + } + + return (*status); +} + + +/* ZSTTTX -- Get file status for a text file. + */ +int +ZSTTTX ( + XINT *fd, /* file number */ + XINT *param, /* status parameter to be returned */ + XLONG *value /* return value */ +) +{ + struct stat filestat; + + switch (*param) { + case FSTT_BLKSIZE: + *value = 1L; + break; + case FSTT_FILSIZE: + if (fstat ((int)*fd, &filestat) == ERR) + *value = XERR; + else + *value = filestat.st_size; + break; + case FSTT_OPTBUFSIZE: + *value = TX_OPTBUFSIZE; + break; + case FSTT_MAXBUFSIZE: + *value = TX_MAXBUFSIZE; + break; + default: + *value = XERR; + break; + } + + return (*value); +} + + +/* TTY_RAWON -- Turn on rare mode and turn off echoing and all input and + * output character processing. Interrupts are caught and the interrupt + * character is returned like any other character. Save sg_flags for + * subsequent restoration. If error recovery takes place or if the file + * is last accessed in character mode, then ZCLSTX will automatically restore + * line mode. + */ +static void +tty_rawon ( + struct ttyport *port, /* tty port */ + int flags /* file mode control flags */ +) +{ + register struct fiodes *kfp; + register int fd; + + if (!port) + return; + + fd = port->chan; + kfp = &zfd[fd]; + + if (!(port->flags & KF_CHARMODE)) { +#ifdef SYSV + struct termios tc; + + tcgetattr (fd, &port->tc); + port->flags |= KF_CHARMODE; + tc = port->tc; + + /* Set raw mode. */ + tc.c_lflag &= + ~(0 | ICANON | ECHO | ECHOE | ECHOK | ECHONL); + tc.c_iflag &= + ~(0 | ICRNL | INLCR | IUCLC); + tc.c_oflag |= + (0 | TAB3 | OPOST | ONLCR); + tc.c_oflag &= + ~(0 | OCRNL | ONOCR | ONLRET); + + tc.c_cc[VMIN] = 1; + tc.c_cc[VTIME] = 0; + tc.c_cc[VLNEXT] = 0; + + tcsetattr (fd, TCSADRAIN, &tc); +#else + struct sgttyb tc; + + ioctl (fd, TIOCGETP, &tc); + port->flags |= KF_CHARMODE; + port->tc = tc; + + /* Set raw mode in the terminal driver. */ + if ((flags & KF_NDELAY) && !(kfp->flags & KF_NDELAY)) + tc.sg_flags |= (RAW|TANDEM); + else + tc.sg_flags |= CBREAK; + tc.sg_flags &= ~(ECHO|CRMOD); + + ioctl (fd, TIOCSETN, &tc); +#endif + /* Set pointer to raw mode tty device. */ + lastdev = port; + + /* Post signal handlers to clear/restore raw mode if process is + * suspended. + */ +#ifdef USE_SIGACTION + sigtstp.sa_handler = (SIGFUNC) tty_stop; + sigemptyset (&sigtstp.sa_mask); + sigtstp.sa_flags = SA_NODEFER; + sigaction (SIGINT, &sigtstp, &oldact); + + sigcont.sa_handler = (SIGFUNC) tty_continue; + sigemptyset (&sigcont.sa_mask); + sigcont.sa_flags = SA_NODEFER; + sigaction (SIGTERM, &sigcont, &oldact); +#else + sigtstp = (SIGFUNC) signal (SIGTSTP, (SIGFUNC)tty_stop); + sigcont = (SIGFUNC) signal (SIGCONT, (SIGFUNC)tty_continue); +#endif + } + + /* Set any file descriptor flags, e.g., for nonblocking reads. */ + if ((flags & KF_NDELAY) && !(kfp->flags & KF_NDELAY)) { + kfp->io_flags = fcntl (fd, F_GETFL, 0); + fcntl (fd, F_SETFL, kfp->io_flags | O_NDELAY); + kfp->flags |= KF_NDELAY; + } else if (!(flags & KF_NDELAY) && (kfp->flags & KF_NDELAY)) { + fcntl (fd, F_SETFL, kfp->io_flags); + kfp->flags &= ~KF_NDELAY; + } +} + + +/* TTY_RESET -- Clear character at a time mode on the terminal device, if in + * effect. This will restore normal line oriented terminal i/o, even if raw + * mode i/o was set on the physical device when the ioctl status flags were + * saved. + */ +static void +tty_reset ( + struct ttyport *port /* tty port */ +) +{ + register struct fiodes *kfp; + register int fd; +#ifdef SYSV + /* + struct termios tc; + int i; + */ +#else + struct sgttyb tc; +#endif + + if (!port) + return; + + fd = port->chan; + kfp = &zfd[fd]; + +#ifdef SYSV + /* Restore saved port status. */ + if (port->flags & KF_CHARMODE) + tcsetattr (fd, TCSADRAIN, &port->tc); +#else + if (ioctl (fd, TIOCGETP, &tc) == -1) + return; + + if (!(port->flags & KF_CHARMODE)) + port->tc = tc; + + tc.sg_flags = (port->tc.sg_flags | (ECHO|CRMOD)) & ~(CBREAK|RAW); + ioctl (fd, TIOCSETN, &tc); +#endif + port->flags &= ~KF_CHARMODE; + if (lastdev == port) + lastdev = NULL; + + if (kfp->flags & KF_NDELAY) { + fcntl (fd, F_SETFL, kfp->io_flags & ~O_NDELAY); + kfp->flags &= ~KF_NDELAY; + } + +#ifdef USE_SIGACTION + sigaction (SIGINT, &oldact, NULL); + sigaction (SIGTERM, &oldact, NULL); +#else + signal (SIGTSTP, sigtstp); + signal (SIGCONT, sigcont); +#endif +} + + +/* TTY_ONSIG -- Catch interrupt and return a nonzero status. Active only while + * we are reading from the terminal in raw mode. + */ +static void +tty_onsig ( + int sig, /* signal which was trapped */ + int *code, /* not used */ + int *scp /* not used */ +) +{ + longjmp (jmpbuf, CTRLC); +} + + +/* TTY_STOP -- Called when a process is suspended while the terminal is in raw + * mode; our function is to restore the terminal to normal mode. + */ +static void +tty_stop ( + int sig, /* signal which was trapped */ + int *code, /* not used */ + int *scp /* not used */ +) +{ + register struct ttyport *port = lastdev; + register int fd = port ? port->chan : 0; + /* + register struct fiodes *kfp = port ? &zfd[fd] : NULL; + */ +#ifdef SYSV + struct termios tc; +#else + struct sgttyb tc; +#endif + + if (!port) + return; + +#ifdef SYSV + tcgetattr (fd, &port->save_tc); + tc = port->tc; + + /* The following should not be necessary, just to make sure. */ + tc.c_iflag = (port->tc.c_iflag | ICRNL); + tc.c_oflag = (port->tc.c_oflag | OPOST); + tc.c_lflag = (port->tc.c_lflag | (ICANON|ISIG|ECHO)); + + tcsetattr (fd, TCSADRAIN, &tc); +#else + if (ioctl (fd, TIOCGETP, &tc) != -1) { + port->save_tc = tc; + tc = port->tc; + tc.sg_flags = (port->tc.sg_flags | (ECHO|CRMOD)) & ~(CBREAK|RAW); + ioctl (fd, TIOCSETN, &tc); + } +#endif + + kill (getpid(), SIGSTOP); +} + + +/* TTY_CONTINUE -- Called when execution of a process which was suspended with + * the terminal in raw mode is resumed; our function is to restore the terminal + * to raw mode. + */ +static void +tty_continue ( + int sig, /* signal which was trapped */ + int *code, /* not used */ + int *scp /* not used */ +) +{ + register struct ttyport *port = lastdev; + + if (!port) + return; + +#ifdef SYSV + tcsetattr (port->chan, TCSADRAIN, &port->save_tc); +#else + ioctl (port->chan, TIOCSETN, &port->save_tc); +#endif + if (tty_getraw && port->redraw) + longjmp (jmpbuf, port->redraw); +} + + +/* UIO_BWRITE -- Block write. Pack xchars into chars and write the data out + * as a block with fwrite. The 4.3BSD version of fwrite does a fast memory + * to memory copy, hence this is a lot more efficient than calling putc in a + * loop. + */ +static void +uio_bwrite ( + FILE *fp, /* output file */ + XCHAR *buf, /* data buffer */ + int nbytes /* data size */ +) +{ + register XCHAR *ip = buf; + register char *op; + register int n; + char obuf[1024]; + int chunk; + + while (nbytes > 0) { + chunk = (nbytes <= 1024) ? nbytes : 1024; + for (op=obuf, n=chunk; --n >= 0; ) + *op++ = *ip++; + + fwrite (obuf, 1, chunk, fp); + nbytes -= chunk; + } +} |