| /* |
| * Copyright (c) 2009-2010 Todd C. Miller <Todd.Miller@courtesan.com> |
| * |
| * Permission to use, copy, modify, and distribute this software for any |
| * purpose with or without fee is hereby granted, provided that the above |
| * copyright notice and this permission notice appear in all copies. |
| * |
| * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
| * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
| * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
| * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
| * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
| * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
| */ |
| |
| #include <config.h> |
| |
| #include <sys/types.h> |
| #include <sys/param.h> |
| #include <stdio.h> |
| #ifdef STDC_HEADERS |
| # include <stdlib.h> |
| # include <stddef.h> |
| #else |
| # ifdef HAVE_STDLIB_H |
| # include <stdlib.h> |
| # endif |
| #endif /* STDC_HEADERS */ |
| #ifdef HAVE_STRING_H |
| # if defined(HAVE_MEMORY_H) && !defined(STDC_HEADERS) |
| # include <memory.h> |
| # endif |
| # include <string.h> |
| #endif /* HAVE_STRING_H */ |
| #ifdef HAVE_STRINGS_H |
| # include <strings.h> |
| #endif /* HAVE_STRINGS_H */ |
| #ifdef HAVE_TERMIOS_H |
| # include <termios.h> |
| #else |
| # ifdef HAVE_TERMIO_H |
| # include <termio.h> |
| # else |
| # include <sgtty.h> |
| # include <sys/ioctl.h> |
| # endif /* HAVE_TERMIO_H */ |
| #endif /* HAVE_TERMIOS_H */ |
| |
| #include "sudo.h" |
| |
| #ifndef TCSASOFT |
| # define TCSASOFT 0 |
| #endif |
| #ifndef ECHONL |
| # define ECHONL 0 |
| #endif |
| #ifndef IEXTEN |
| # define IEXTEN 0 |
| #endif |
| #ifndef IUCLC |
| # define IUCLC 0 |
| #endif |
| |
| #ifndef _POSIX_VDISABLE |
| # ifdef VDISABLE |
| # define _POSIX_VDISABLE VDISABLE |
| # else |
| # define _POSIX_VDISABLE 0 |
| # endif |
| #endif |
| |
| /* |
| * Compat macros for non-termios systems. |
| */ |
| #ifndef HAVE_TERMIOS_H |
| # ifdef HAVE_TERMIO_H |
| # undef termios |
| # define termios termio |
| # define tcgetattr(f, t) ioctl(f, TCGETA, t) |
| # define tcsetattr(f, a, t) ioctl(f, a, t) |
| # undef TCSAFLUSH |
| # define TCSAFLUSH TCSETAF |
| # undef TCSADRAIN |
| # define TCSADRAIN TCSETAW |
| # else /* SGTTY */ |
| # undef termios |
| # define termios sgttyb |
| # define c_lflag sg_flags |
| # define tcgetattr(f, t) ioctl(f, TIOCGETP, t) |
| # define tcsetattr(f, a, t) ioctl(f, a, t) |
| # undef TCSAFLUSH |
| # define TCSAFLUSH TIOCSETP |
| # undef TCSADRAIN |
| # define TCSADRAIN TIOCSETN |
| # endif /* HAVE_TERMIO_H */ |
| #endif /* HAVE_TERMIOS_H */ |
| |
| typedef struct termios sudo_term_t; |
| |
| static sudo_term_t term, oterm; |
| static int changed; |
| int term_erase; |
| int term_kill; |
| |
| int |
| term_restore(fd, flush) |
| int fd; |
| int flush; |
| { |
| if (changed) { |
| int flags = TCSASOFT; |
| flags |= flush ? TCSAFLUSH : TCSADRAIN; |
| if (tcsetattr(fd, flags, &oterm) != 0) |
| return(0); |
| changed = 0; |
| } |
| return(1); |
| } |
| |
| int |
| term_noecho(fd) |
| int fd; |
| { |
| if (!changed && tcgetattr(fd, &oterm) != 0) |
| return(0); |
| (void) memcpy(&term, &oterm, sizeof(term)); |
| CLR(term.c_lflag, ECHO|ECHONL); |
| #ifdef VSTATUS |
| term.c_cc[VSTATUS] = _POSIX_VDISABLE; |
| #endif |
| if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { |
| changed = 1; |
| return(1); |
| } |
| return(0); |
| } |
| |
| #if defined(HAVE_TERMIOS_H) || defined(HAVE_TERMIO_H) |
| |
| int |
| term_raw(fd, isig) |
| int fd; |
| int isig; |
| { |
| struct termios term; |
| |
| if (!changed && tcgetattr(fd, &oterm) != 0) |
| return(0); |
| (void) memcpy(&term, &oterm, sizeof(term)); |
| /* Set terminal to raw mode */ |
| term.c_cc[VMIN] = 1; |
| term.c_cc[VTIME] = 0; |
| CLR(term.c_lflag, ECHO | ECHONL | ICANON | ISIG | IEXTEN); |
| if (isig) |
| SET(term.c_lflag, ISIG); |
| CLR(term.c_iflag, ICRNL | IGNCR | INLCR | IUCLC | IXON); |
| if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { |
| changed = 1; |
| return(1); |
| } |
| return(0); |
| } |
| |
| int |
| term_cbreak(fd) |
| int fd; |
| { |
| if (!changed && tcgetattr(fd, &oterm) != 0) |
| return(0); |
| (void) memcpy(&term, &oterm, sizeof(term)); |
| /* Set terminal to half-cooked mode */ |
| term.c_cc[VMIN] = 1; |
| term.c_cc[VTIME] = 0; |
| CLR(term.c_lflag, ECHO | ECHONL | ICANON | IEXTEN); |
| SET(term.c_lflag, ISIG); |
| #ifdef VSTATUS |
| term.c_cc[VSTATUS] = _POSIX_VDISABLE; |
| #endif |
| if (tcsetattr(fd, TCSADRAIN|TCSASOFT, &term) == 0) { |
| term_erase = term.c_cc[VERASE]; |
| term_kill = term.c_cc[VKILL]; |
| changed = 1; |
| return(1); |
| } |
| return(0); |
| } |
| |
| int |
| term_copy(src, dst) |
| int src; |
| int dst; |
| { |
| struct termios tt; |
| |
| if (tcgetattr(src, &tt) != 0) |
| return(0); |
| /* XXX - add TCSANOW compat define */ |
| if (tcsetattr(dst, TCSANOW|TCSASOFT, &tt) != 0) |
| return(0); |
| return(1); |
| } |
| |
| #else /* SGTTY */ |
| |
| int |
| term_raw(fd, isig) |
| int fd; |
| int isig; |
| { |
| if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) |
| return(0); |
| (void) memcpy(&term, &oterm, sizeof(term)); |
| /* Set terminal to raw mode */ |
| /* XXX - how to support isig? */ |
| CLR(term.c_lflag, ECHO); |
| SET(term.sg_flags, RAW); |
| if (ioctl(fd, TIOCSETP, &term) == 0) { |
| changed = 1; |
| return(1); |
| } |
| return(0); |
| } |
| |
| int |
| term_cbreak(fd) |
| int fd; |
| { |
| if (!changed && ioctl(fd, TIOCGETP, &oterm) != 0) |
| return(0); |
| (void) memcpy(&term, &oterm, sizeof(term)); |
| /* Set terminal to half-cooked mode */ |
| CLR(term.c_lflag, ECHO); |
| SET(term.sg_flags, CBREAK); |
| if (ioctl(fd, TIOCSETP, &term) == 0) { |
| term_erase = term.sg_erase; |
| term_kill = term.sg_kill; |
| changed = 1; |
| return(1); |
| } |
| return(0); |
| } |
| |
| int |
| term_copy(src, dst) |
| int src; |
| int dst; |
| { |
| struct sgttyb b; |
| struct tchars tc; |
| struct ltchars lc; |
| int l, lb; |
| |
| if (ioctl(src, TIOCGETP, &b) != 0 || ioctl(src, TIOCGETC, &tc) != 0 || |
| ioctl(src, TIOCGETD, &l) != 0 || ioctl(src, TIOCGLTC, &lc) != 0 || |
| ioctl(src, TIOCLGET, &lb)) { |
| return(0); |
| } |
| if (ioctl(dst, TIOCSETP, &b) != 0 || ioctl(dst, TIOCSETC, &tc) != 0 || |
| ioctl(dst, TIOCSLTC, &lc) != 0 || ioctl(dst, TIOCLSET, &lb) != 0 || |
| ioctl(dst, TIOCSETD, &l) != 0) { |
| return(0); |
| } |
| return(1); |
| } |
| |
| #endif |