17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5de81e71eSTim Marsland  * Common Development and Distribution License (the "License").
6de81e71eSTim Marsland  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21de81e71eSTim Marsland 
227c478bd9Sstevel@tonic-gate /*
23de81e71eSTim Marsland  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
273b6e0a59SMatt Amdur /*
283b6e0a59SMatt Amdur  * Copyright (c) 2012 by Delphix. All rights reserved.
29448027ebSBryan Cantrill  * Copyright 2017 Joyent, Inc.
303b6e0a59SMatt Amdur  */
313b6e0a59SMatt Amdur 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * Terminal I/O Backend
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * Terminal editing backend for standard input.  The terminal i/o backend is
367c478bd9Sstevel@tonic-gate  * actually built on top of two other i/o backends: one for raw input and
377c478bd9Sstevel@tonic-gate  * another for raw output (presumably stdin and stdout).  When IOP_READ is
387c478bd9Sstevel@tonic-gate  * invoked, the terminal backend enters a read-loop in which it can perform
397c478bd9Sstevel@tonic-gate  * command-line editing and access a history buffer.  Once a newline is read,
407c478bd9Sstevel@tonic-gate  * the entire buffered command-line is returned to the caller.  The termio
417c478bd9Sstevel@tonic-gate  * code makes use of a command buffer (see mdb_cmdbuf.c) to maintain and
427c478bd9Sstevel@tonic-gate  * manipulate the state of a command line, and store it for re-use in a
437c478bd9Sstevel@tonic-gate  * history list.  The termio code manipulates the terminal to keep it in
447c478bd9Sstevel@tonic-gate  * sync with the contents of the command buffer, and moves the cursor in
457c478bd9Sstevel@tonic-gate  * response to editing commands.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * The terminal backend is also responsible for maintaining and manipulating
48bbf21555SRichard Lowe  * the settings (see stty(1) and termio(4I)) associated with the terminal.
497c478bd9Sstevel@tonic-gate  * The debugger makes use of four distinct sets of terminal attributes:
507c478bd9Sstevel@tonic-gate  *
517c478bd9Sstevel@tonic-gate  * (1) the settings used by the debugger's parent process (tio_ptios),
527c478bd9Sstevel@tonic-gate  * (2) the settings used by a controlled child process (tio_ctios),
537c478bd9Sstevel@tonic-gate  * (3) the settings used for reading and command-line editing (tio_rtios), and
547c478bd9Sstevel@tonic-gate  * (4) the settings used when mdb dcmds are executing (tio_dtios).
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * The parent settings (1) are read from the terminal during initialization.
577c478bd9Sstevel@tonic-gate  * These settings are restored before the debugger exits or when it is stopped
587c478bd9Sstevel@tonic-gate  * by SIGTSTP.  The child settings (2) are initially a copy of (1), but are
597c478bd9Sstevel@tonic-gate  * then restored prior to continuing execution of a victim process.  The new
607c478bd9Sstevel@tonic-gate  * settings (3) and (4) are both derived from (1).  The raw settings (3) used
617c478bd9Sstevel@tonic-gate  * for reading from the terminal allow the terminal code to respond instantly
627c478bd9Sstevel@tonic-gate  * to keypresses and perform all the necessary handling.  The dcmd settings (4)
637c478bd9Sstevel@tonic-gate  * are essentially the same as (1), except that we make sure ISIG is enabled
647c478bd9Sstevel@tonic-gate  * so that we will receive asynchronous SIGINT notification from the terminal
657c478bd9Sstevel@tonic-gate  * driver if the user types the interrupt character (typically ^C).
667c478bd9Sstevel@tonic-gate  */
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate #include <setjmp.h>
697c478bd9Sstevel@tonic-gate #include <unistd.h>
707c478bd9Sstevel@tonic-gate #include <stdlib.h>
717c478bd9Sstevel@tonic-gate #include <limits.h>
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate #include <mdb/mdb_types.h>
747c478bd9Sstevel@tonic-gate #include <mdb/mdb_cmdbuf.h>
757c478bd9Sstevel@tonic-gate #include <mdb/mdb_err.h>
767c478bd9Sstevel@tonic-gate #include <mdb/mdb_io_impl.h>
777c478bd9Sstevel@tonic-gate #include <mdb/mdb_debug.h>
787c478bd9Sstevel@tonic-gate #include <mdb/mdb_signal.h>
797c478bd9Sstevel@tonic-gate #include <mdb/mdb_callb.h>
807c478bd9Sstevel@tonic-gate #include <mdb/mdb_stdlib.h>
817c478bd9Sstevel@tonic-gate #include <mdb/mdb_string.h>
827c478bd9Sstevel@tonic-gate #include <mdb/mdb_modapi.h>
837c478bd9Sstevel@tonic-gate #include <mdb/mdb_frame.h>
843b6e0a59SMatt Amdur #include <mdb/mdb_tab.h>
857c478bd9Sstevel@tonic-gate #include <mdb/mdb.h>
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate #ifdef ERR
887c478bd9Sstevel@tonic-gate #undef ERR
897c478bd9Sstevel@tonic-gate #endif
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate #include <curses.h>
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate #define	KEY_ESC	(0x01b)			/* Escape key code */
947c478bd9Sstevel@tonic-gate #define	KEY_DEL (0x07f)			/* ASCII DEL key code */
957c478bd9Sstevel@tonic-gate 
96892f67e4SJoshua M. Clulow /*
97892f67e4SJoshua M. Clulow  * These macros support the use of various ranges within the "tio_keymap"
98892f67e4SJoshua M. Clulow  * member of "termio_data_t" objects.  This array maps from an input byte, or
99892f67e4SJoshua M. Clulow  * special control code, to the appropriate terminal handling callback.  The
100892f67e4SJoshua M. Clulow  * array has KEY_MAX (0x1ff) entries, partitioned as follows:
101892f67e4SJoshua M. Clulow  *
102892f67e4SJoshua M. Clulow  *     0 -  7f		7-bit ASCII byte
103892f67e4SJoshua M. Clulow  *    80 -  ff	META()	ASCII byte with Meta key modifier
104892f67e4SJoshua M. Clulow  *   100 - 119	KPAD()	Alphabetic character received as part of a single-byte
105892f67e4SJoshua M. Clulow  *			cursor control sequence, e.g. ESC [ A
106892f67e4SJoshua M. Clulow  *   11a - 123	FKEY()	Numeric character received as part of a function key
107892f67e4SJoshua M. Clulow  *			control sequence, e.g. ESC [ 4 ~
108892f67e4SJoshua M. Clulow  *   124 - 1ff		Unused
109892f67e4SJoshua M. Clulow  */
110892f67e4SJoshua M. Clulow #define	META(c)		(((c) & 0x7f) | 0x80)
111892f67e4SJoshua M. Clulow #define	KPAD(c)		(((c) < 'A' || (c) > 'Z') ? 0 : ((c) - 'A' + 0x100))
112892f67e4SJoshua M. Clulow #define	FKEY(c)		(((c) < '0' || (c) > '9') ? 0 : ((c) - '0' + 0x11a))
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * These macros allow for composition of control sequences for xterm and other
1167c478bd9Sstevel@tonic-gate  * terminals that support certain features of the VT102 and later VT terminals.
1177c478bd9Sstevel@tonic-gate  * Refer to the classic monograph "Xterm Control Sequences" for more info.
1187c478bd9Sstevel@tonic-gate  */
1197c478bd9Sstevel@tonic-gate #define	TI_DECSET(Pm) "\033[?" Pm "h"	/* Compose DEC private mode set */
1207c478bd9Sstevel@tonic-gate #define	TI_DECRST(Pm) "\033[?" Pm "l"	/* Compose DEC private mode reset */
1217c478bd9Sstevel@tonic-gate #define	TI_DECSAV(Pm) "\033[?" Pm "s"	/* Compose DEC private mode save */
1227c478bd9Sstevel@tonic-gate #define	TI_DECRES(Pm) "\033[?" Pm "r"	/* Compose DEC private mode restore */
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate #define	TI_DECCOLM		"3"	/* Ps = DEC 80/132 column mode */
1257c478bd9Sstevel@tonic-gate #define	TI_COLENAB		"40"	/* Ps = 80/132 column switch enable */
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate #define	TIO_DEFAULT_ROWS	24	/* Default number of rows */
1287c478bd9Sstevel@tonic-gate #define	TIO_DEFAULT_COLS	80	/* Default number of columns */
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate typedef union termio_attr_val {
1317c478bd9Sstevel@tonic-gate 	const char *at_str;		/* String value */
1327c478bd9Sstevel@tonic-gate 	int at_val;			/* Integer or boolean value */
1337c478bd9Sstevel@tonic-gate } termio_attr_val_t;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate typedef struct termio_info {
1367c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cub1;	/* Move back one space */
1377c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cuf1;	/* Move forward one space */
1387c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cuu1;	/* Move up one line */
1397c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cud1;	/* Move down one line */
1407c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_pad;	/* Pad character */
1417c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_el;	/* Clear to end-of-line */
1427c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_am;	/* Automatic right margin? */
1437c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_bw;	/* Backward motion at left edge? */
1447c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_npc;	/* No padding character? */
145448027ebSBryan Cantrill 	termio_attr_val_t ti_xenl;	/* Newline ignored at autowrap? */
1467c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_xon;	/* Use xon/xoff handshaking? */
1477c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cols;	/* # of columns */
1487c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_lines;	/* # of rows */
1497c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_pb;	/* Lowest baud rate that requires pad */
1507c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_smso;	/* Set standout mode */
1517c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rmso;	/* Remove standout mode */
1527c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_smul;	/* Set underline mode */
1537c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rmul;	/* Remove underline mode */
1547c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_enacs;	/* Enable alternate character set */
1557c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_smacs;	/* Set alternate character set */
1567c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rmacs;	/* Remove alternate character set */
1577c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_smcup;	/* Set mode where cup is active */
1587c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rmcup;	/* Remove mode where cup is active */
1597c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rev;	/* Set reverse video mode */
1607c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_bold;	/* Set bold text mode */
1617c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_dim;	/* Set dim text mode */
1627c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_sgr0;	/* Remove all video attributes */
1637c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_smir;	/* Set insert mode */
1647c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_rmir;	/* Remove insert mode */
1657c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_ich1;	/* Insert character */
1667c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_ip;	/* Insert pad delay in msecs */
1677c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_clear;	/* Clear screen and home cursor */
1687c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cnorm;	/* Make cursor appear normal */
1697c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_nel;	/* Newline */
1707c478bd9Sstevel@tonic-gate 	termio_attr_val_t ti_cr;	/* Carriage return */
171448027ebSBryan Cantrill 	termio_attr_val_t ti_smam;	/* Turn on automatic margins */
1727c478bd9Sstevel@tonic-gate } termio_info_t;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate typedef enum {
1757c478bd9Sstevel@tonic-gate 	TIO_ATTR_REQSTR,		/* String attribute that is required */
1767c478bd9Sstevel@tonic-gate 	TIO_ATTR_STR,			/* String attribute */
1777c478bd9Sstevel@tonic-gate 	TIO_ATTR_BOOL,			/* Boolean attribute */
1787c478bd9Sstevel@tonic-gate 	TIO_ATTR_INT			/* Integer attribute */
1797c478bd9Sstevel@tonic-gate } termio_attr_type_t;
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate typedef struct termio_attr {
1827c478bd9Sstevel@tonic-gate 	const char *ta_name;		/* Capability name */
1837c478bd9Sstevel@tonic-gate 	termio_attr_type_t ta_type;	/* Capability type */
1847c478bd9Sstevel@tonic-gate 	termio_attr_val_t *ta_valp;	/* String pointer location */
1857c478bd9Sstevel@tonic-gate } termio_attr_t;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate struct termio_data;
1887c478bd9Sstevel@tonic-gate typedef const char *(*keycb_t)(struct termio_data *, int);
1897c478bd9Sstevel@tonic-gate typedef void (*putp_t)(struct termio_data *, const char *, uint_t);
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate #define	TIO_FINDHIST	0x01		/* Find-history-mode */
1927c478bd9Sstevel@tonic-gate #define	TIO_AUTOWRAP	0x02		/* Terminal has autowrap */
1937c478bd9Sstevel@tonic-gate #define	TIO_BACKLEFT	0x04		/* Terminal can go back at left edge */
1947c478bd9Sstevel@tonic-gate #define	TIO_INSERT	0x08		/* Terminal has insert mode */
1957c478bd9Sstevel@tonic-gate #define	TIO_USECUP	0x10		/* Use smcup/rmcup sequences */
1967c478bd9Sstevel@tonic-gate #define	TIO_TTYWARN	0x20		/* Warnings about tty issued */
1977c478bd9Sstevel@tonic-gate #define	TIO_CAPWARN	0x40		/* Warnings about terminfo issued */
1987c478bd9Sstevel@tonic-gate #define	TIO_XTERM	0x80		/* Terminal is xterm compatible */
1993b6e0a59SMatt Amdur #define	TIO_TAB		0x100		/* Tab completion mode */
200448027ebSBryan Cantrill #define	TIO_LAZYWRAP	0x200		/* Lazy cursor on autowrap */
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static const mdb_bitmask_t tio_flag_masks[] = {
2037c478bd9Sstevel@tonic-gate 	{ "FINDHIST", TIO_FINDHIST, TIO_FINDHIST },
2047c478bd9Sstevel@tonic-gate 	{ "AUTOWRAP", TIO_AUTOWRAP, TIO_AUTOWRAP },
2057c478bd9Sstevel@tonic-gate 	{ "BACKLEFT", TIO_BACKLEFT, TIO_BACKLEFT },
2067c478bd9Sstevel@tonic-gate 	{ "INSERT", TIO_INSERT, TIO_INSERT },
2077c478bd9Sstevel@tonic-gate 	{ "USECUP", TIO_USECUP, TIO_USECUP },
2087c478bd9Sstevel@tonic-gate 	{ "TTYWARN", TIO_TTYWARN, TIO_TTYWARN },
2097c478bd9Sstevel@tonic-gate 	{ "CAPWARN", TIO_CAPWARN, TIO_CAPWARN },
2107c478bd9Sstevel@tonic-gate 	{ "XTERM", TIO_XTERM, TIO_XTERM },
211448027ebSBryan Cantrill 	{ "TAB", TIO_TAB, TIO_TAB },
212448027ebSBryan Cantrill 	{ "LAZYWRAP", TIO_LAZYWRAP, TIO_LAZYWRAP },
2137c478bd9Sstevel@tonic-gate 	{ NULL, 0, 0 }
2147c478bd9Sstevel@tonic-gate };
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate typedef struct termio_data {
2177c478bd9Sstevel@tonic-gate 	mdb_io_t *tio_io;		/* Pointer back to containing i/o */
2187c478bd9Sstevel@tonic-gate 	mdb_io_t *tio_out_io;		/* Terminal output backend */
2197c478bd9Sstevel@tonic-gate 	mdb_io_t *tio_in_io;		/* Terminal input backend */
2207c478bd9Sstevel@tonic-gate 	mdb_iob_t *tio_out;		/* I/o buffer for terminal output */
2217c478bd9Sstevel@tonic-gate 	mdb_iob_t *tio_in;		/* I/o buffer for terminal input */
2227c478bd9Sstevel@tonic-gate 	mdb_iob_t *tio_link;		/* I/o buffer to resize on WINCH */
223892f67e4SJoshua M. Clulow 	keycb_t tio_keymap[KEY_MAX];	/* Keymap (see comments atop file) */
2247c478bd9Sstevel@tonic-gate 	mdb_cmdbuf_t tio_cmdbuf;	/* Editable command-line buffer */
2257c478bd9Sstevel@tonic-gate 	struct termios tio_ptios;	/* Parent terminal settings */
2267c478bd9Sstevel@tonic-gate 	struct termios tio_ctios;	/* Child terminal settings */
2277c478bd9Sstevel@tonic-gate 	struct termios tio_rtios;	/* Settings for read loop */
2287c478bd9Sstevel@tonic-gate 	struct termios tio_dtios;	/* Settings for dcmd execution */
2297c478bd9Sstevel@tonic-gate 	sigjmp_buf tio_env;		/* Read loop setjmp(3c) environment */
2307c478bd9Sstevel@tonic-gate 	termio_info_t tio_info;		/* Terminal attribute strings */
2317c478bd9Sstevel@tonic-gate 	char *tio_attrs;		/* Attribute string buffer */
2327c478bd9Sstevel@tonic-gate 	size_t tio_attrslen;		/* Length in bytes of tio_attrs */
2337c478bd9Sstevel@tonic-gate 	const char *tio_prompt;		/* Prompt string for this read */
2347c478bd9Sstevel@tonic-gate 	size_t tio_promptlen;		/* Length of prompt string */
2357c478bd9Sstevel@tonic-gate 	size_t tio_rows;		/* Terminal height */
2367c478bd9Sstevel@tonic-gate 	size_t tio_cols;		/* Terminal width */
2377c478bd9Sstevel@tonic-gate 	size_t tio_x;			/* Cursor x coordinate */
2387c478bd9Sstevel@tonic-gate 	size_t tio_y;			/* Cursor y coordinate */
2397c478bd9Sstevel@tonic-gate 	size_t tio_max_x;		/* Previous maximum x coordinate */
2407c478bd9Sstevel@tonic-gate 	size_t tio_max_y;		/* Previous maximum y coordinate */
2417c478bd9Sstevel@tonic-gate 	int tio_intr;			/* Interrupt char */
2427c478bd9Sstevel@tonic-gate 	int tio_quit;			/* Quit char */
2437c478bd9Sstevel@tonic-gate 	int tio_erase;			/* Erase char */
2447c478bd9Sstevel@tonic-gate 	int tio_werase;			/* Word-erase char */
2457c478bd9Sstevel@tonic-gate 	int tio_kill;			/* Kill char */
2467c478bd9Sstevel@tonic-gate 	int tio_eof;			/* End-of-file char */
2477c478bd9Sstevel@tonic-gate 	int tio_susp;			/* Suspend char */
2487c478bd9Sstevel@tonic-gate 	uint_t tio_flags;		/* Miscellaneous flags */
2497c478bd9Sstevel@tonic-gate 	volatile mdb_bool_t tio_active;	/* Flag denoting read loop active */
2507c478bd9Sstevel@tonic-gate 	volatile mdb_bool_t tio_rti_on;	/* Flag denoting rtios in use */
2517c478bd9Sstevel@tonic-gate 	putp_t tio_putp;		/* termio_tput() subroutine */
2527c478bd9Sstevel@tonic-gate 	uint_t tio_baud;		/* Baud rate (chars per second) */
2537c478bd9Sstevel@tonic-gate 	uint_t tio_usecpc;		/* Usecs per char at given baud rate */
2547c478bd9Sstevel@tonic-gate 	pid_t tio_opgid;		/* Old process group id for terminal */
2557c478bd9Sstevel@tonic-gate 	uint_t tio_suspended;		/* termio_suspend_tty() nesting count */
2567c478bd9Sstevel@tonic-gate } termio_data_t;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate static ssize_t termio_read(mdb_io_t *, void *, size_t);
2597c478bd9Sstevel@tonic-gate static ssize_t termio_write(mdb_io_t *, const void *, size_t);
2607c478bd9Sstevel@tonic-gate static off64_t termio_seek(mdb_io_t *, off64_t, int);
2617c478bd9Sstevel@tonic-gate static int termio_ctl(mdb_io_t *, int, void *);
2627c478bd9Sstevel@tonic-gate static void termio_close(mdb_io_t *);
2637c478bd9Sstevel@tonic-gate static const char *termio_name(mdb_io_t *);
2647c478bd9Sstevel@tonic-gate static void termio_link(mdb_io_t *, mdb_iob_t *);
2657c478bd9Sstevel@tonic-gate static void termio_unlink(mdb_io_t *, mdb_iob_t *);
2667c478bd9Sstevel@tonic-gate static int termio_setattr(mdb_io_t *, int, uint_t);
2677c478bd9Sstevel@tonic-gate static void termio_suspend(mdb_io_t *);
2687c478bd9Sstevel@tonic-gate static void termio_resume(mdb_io_t *);
2697c478bd9Sstevel@tonic-gate 
2707c478bd9Sstevel@tonic-gate static void termio_suspend_tty(termio_data_t *, struct termios *);
2717c478bd9Sstevel@tonic-gate static void termio_resume_tty(termio_data_t *, struct termios *);
2727c478bd9Sstevel@tonic-gate 
2737c478bd9Sstevel@tonic-gate static void termio_putp(termio_data_t *, const char *, uint_t);
2747c478bd9Sstevel@tonic-gate static void termio_puts(termio_data_t *, const char *, uint_t);
2757c478bd9Sstevel@tonic-gate static void termio_tput(termio_data_t *, const char *, uint_t);
2767c478bd9Sstevel@tonic-gate static void termio_addch(termio_data_t *, char, size_t);
2777c478bd9Sstevel@tonic-gate static void termio_insch(termio_data_t *, char, size_t);
2787c478bd9Sstevel@tonic-gate static void termio_mvcur(termio_data_t *);
2797c478bd9Sstevel@tonic-gate static void termio_bspch(termio_data_t *);
2807c478bd9Sstevel@tonic-gate static void termio_delch(termio_data_t *);
2817c478bd9Sstevel@tonic-gate static void termio_clear(termio_data_t *);
2827c478bd9Sstevel@tonic-gate static void termio_redraw(termio_data_t *);
2837c478bd9Sstevel@tonic-gate static void termio_prompt(termio_data_t *);
2847c478bd9Sstevel@tonic-gate 
2853b6e0a59SMatt Amdur static const char *termio_tab(termio_data_t *, int);
2867c478bd9Sstevel@tonic-gate static const char *termio_insert(termio_data_t *, int);
2877c478bd9Sstevel@tonic-gate static const char *termio_accept(termio_data_t *, int);
2887c478bd9Sstevel@tonic-gate static const char *termio_backspace(termio_data_t *, int);
2897c478bd9Sstevel@tonic-gate static const char *termio_delchar(termio_data_t *, int);
2907c478bd9Sstevel@tonic-gate static const char *termio_fwdchar(termio_data_t *, int);
2917c478bd9Sstevel@tonic-gate static const char *termio_backchar(termio_data_t *, int);
2927c478bd9Sstevel@tonic-gate static const char *termio_transpose(termio_data_t *, int);
2937c478bd9Sstevel@tonic-gate static const char *termio_home(termio_data_t *, int);
2947c478bd9Sstevel@tonic-gate static const char *termio_end(termio_data_t *, int);
2957c478bd9Sstevel@tonic-gate static const char *termio_fwdword(termio_data_t *, int);
2967c478bd9Sstevel@tonic-gate static const char *termio_backword(termio_data_t *, int);
2977c478bd9Sstevel@tonic-gate static const char *termio_kill(termio_data_t *, int);
2987c478bd9Sstevel@tonic-gate static const char *termio_killfwdword(termio_data_t *, int);
2997c478bd9Sstevel@tonic-gate static const char *termio_killbackword(termio_data_t *, int);
3007c478bd9Sstevel@tonic-gate static const char *termio_reset(termio_data_t *, int);
3017c478bd9Sstevel@tonic-gate static const char *termio_widescreen(termio_data_t *, int);
3027c478bd9Sstevel@tonic-gate static const char *termio_prevhist(termio_data_t *, int);
3037c478bd9Sstevel@tonic-gate static const char *termio_nexthist(termio_data_t *, int);
3047c478bd9Sstevel@tonic-gate static const char *termio_accel(termio_data_t *, int);
3057c478bd9Sstevel@tonic-gate static const char *termio_findhist(termio_data_t *, int);
3067c478bd9Sstevel@tonic-gate static const char *termio_refresh(termio_data_t *, int);
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate static const char *termio_intr(termio_data_t *, int);
3097c478bd9Sstevel@tonic-gate static const char *termio_quit(termio_data_t *, int);
3107c478bd9Sstevel@tonic-gate static const char *termio_susp(termio_data_t *, int);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate static void termio_winch(int, siginfo_t *, ucontext_t *, void *);
3137c478bd9Sstevel@tonic-gate static void termio_tstp(int, siginfo_t *, ucontext_t *, void *);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate extern const char *tigetstr(const char *);
3167c478bd9Sstevel@tonic-gate extern int tigetflag(const char *);
3177c478bd9Sstevel@tonic-gate extern int tigetnum(const char *);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static const mdb_io_ops_t termio_ops = {
3200c1b95beSRichard Lowe 	.io_read = termio_read,
3210c1b95beSRichard Lowe 	.io_write = termio_write,
3220c1b95beSRichard Lowe 	.io_seek = termio_seek,
3230c1b95beSRichard Lowe 	.io_ctl = termio_ctl,
3240c1b95beSRichard Lowe 	.io_close = termio_close,
3250c1b95beSRichard Lowe 	.io_name = termio_name,
3260c1b95beSRichard Lowe 	.io_link = termio_link,
3270c1b95beSRichard Lowe 	.io_unlink = termio_unlink,
3280c1b95beSRichard Lowe 	.io_setattr = termio_setattr,
3290c1b95beSRichard Lowe 	.io_suspend = termio_suspend,
3300c1b95beSRichard Lowe 	.io_resume = termio_resume,
3317c478bd9Sstevel@tonic-gate };
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate static termio_info_t termio_info;
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate static const termio_attr_t termio_attrs[] = {
3367c478bd9Sstevel@tonic-gate 	{ "cub1", TIO_ATTR_REQSTR, &termio_info.ti_cub1 },
3377c478bd9Sstevel@tonic-gate 	{ "cuf1", TIO_ATTR_REQSTR, &termio_info.ti_cuf1 },
3387c478bd9Sstevel@tonic-gate 	{ "cuu1", TIO_ATTR_REQSTR, &termio_info.ti_cuu1 },
3397c478bd9Sstevel@tonic-gate 	{ "cud1", TIO_ATTR_REQSTR, &termio_info.ti_cud1 },
3407c478bd9Sstevel@tonic-gate 	{ "pad", TIO_ATTR_STR, &termio_info.ti_pad },
3417c478bd9Sstevel@tonic-gate 	{ "el", TIO_ATTR_REQSTR, &termio_info.ti_el },
3427c478bd9Sstevel@tonic-gate 	{ "am", TIO_ATTR_BOOL, &termio_info.ti_am },
3437c478bd9Sstevel@tonic-gate 	{ "bw", TIO_ATTR_BOOL, &termio_info.ti_bw },
3447c478bd9Sstevel@tonic-gate 	{ "npc", TIO_ATTR_BOOL, &termio_info.ti_npc },
3457c478bd9Sstevel@tonic-gate 	{ "xenl", TIO_ATTR_BOOL, &termio_info.ti_xenl },
3467c478bd9Sstevel@tonic-gate 	{ "xon", TIO_ATTR_BOOL, &termio_info.ti_xon },
3477c478bd9Sstevel@tonic-gate 	{ "cols", TIO_ATTR_INT, &termio_info.ti_cols },
3487c478bd9Sstevel@tonic-gate 	{ "lines", TIO_ATTR_INT, &termio_info.ti_lines },
3497c478bd9Sstevel@tonic-gate 	{ "pb", TIO_ATTR_INT, &termio_info.ti_pb },
3507c478bd9Sstevel@tonic-gate 	{ "smso", TIO_ATTR_STR, &termio_info.ti_smso },
3517c478bd9Sstevel@tonic-gate 	{ "rmso", TIO_ATTR_STR, &termio_info.ti_rmso },
3527c478bd9Sstevel@tonic-gate 	{ "smul", TIO_ATTR_STR, &termio_info.ti_smul },
3537c478bd9Sstevel@tonic-gate 	{ "rmul", TIO_ATTR_STR, &termio_info.ti_rmul },
3547c478bd9Sstevel@tonic-gate 	{ "enacs", TIO_ATTR_STR, &termio_info.ti_enacs },
3557c478bd9Sstevel@tonic-gate 	{ "smacs", TIO_ATTR_STR, &termio_info.ti_smacs },
3567c478bd9Sstevel@tonic-gate 	{ "rmacs", TIO_ATTR_STR, &termio_info.ti_rmacs },
3577c478bd9Sstevel@tonic-gate 	{ "smcup", TIO_ATTR_STR, &termio_info.ti_smcup },
3587c478bd9Sstevel@tonic-gate 	{ "rmcup", TIO_ATTR_STR, &termio_info.ti_rmcup },
3597c478bd9Sstevel@tonic-gate 	{ "rev", TIO_ATTR_STR, &termio_info.ti_rev },
3607c478bd9Sstevel@tonic-gate 	{ "bold", TIO_ATTR_STR, &termio_info.ti_bold },
3617c478bd9Sstevel@tonic-gate 	{ "dim", TIO_ATTR_STR, &termio_info.ti_dim },
3627c478bd9Sstevel@tonic-gate 	{ "sgr0", TIO_ATTR_STR, &termio_info.ti_sgr0 },
3637c478bd9Sstevel@tonic-gate 	{ "smir", TIO_ATTR_STR, &termio_info.ti_smir },
3647c478bd9Sstevel@tonic-gate 	{ "rmir", TIO_ATTR_STR, &termio_info.ti_rmir },
3657c478bd9Sstevel@tonic-gate 	{ "ich1", TIO_ATTR_STR, &termio_info.ti_ich1 },
3667c478bd9Sstevel@tonic-gate 	{ "ip", TIO_ATTR_STR, &termio_info.ti_ip },
3677c478bd9Sstevel@tonic-gate 	{ "clear", TIO_ATTR_STR, &termio_info.ti_clear },
3687c478bd9Sstevel@tonic-gate 	{ "cnorm", TIO_ATTR_STR, &termio_info.ti_cnorm },
3697c478bd9Sstevel@tonic-gate 	{ "nel", TIO_ATTR_STR, &termio_info.ti_nel },
3707c478bd9Sstevel@tonic-gate 	{ "cr", TIO_ATTR_STR, &termio_info.ti_cr },
371448027ebSBryan Cantrill 	{ "smam", TIO_ATTR_STR, &termio_info.ti_smam },
372892ad162SToomas Soome 	{ NULL, 0, NULL }
3737c478bd9Sstevel@tonic-gate };
3747c478bd9Sstevel@tonic-gate 
3757c478bd9Sstevel@tonic-gate /*
3767c478bd9Sstevel@tonic-gate  * One-key accelerators.  Some commands are used so frequently as to need
3777c478bd9Sstevel@tonic-gate  * single-key equivalents.  termio_accelkeys contains a list of the accelerator
3787c478bd9Sstevel@tonic-gate  * keys, with termio_accel listing the accelerated commands.  The array is
3797c478bd9Sstevel@tonic-gate  * indexed by the offset of the accelerator in the macro string, and as such
3807c478bd9Sstevel@tonic-gate  * *must* stay in the same order.
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate static const char *const termio_accelkeys = "[]";
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate static const char *const termio_accelstrings[] = {
3857c478bd9Sstevel@tonic-gate 	"::step over",	/* [ */
3867c478bd9Sstevel@tonic-gate 	"::step"	/* ] */
3877c478bd9Sstevel@tonic-gate };
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate static const char *
termio_accel_lookup(int c)3907c478bd9Sstevel@tonic-gate termio_accel_lookup(int c)
3917c478bd9Sstevel@tonic-gate {
3927c478bd9Sstevel@tonic-gate 	const char *acc;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	if ((acc = strchr(termio_accelkeys, c)) == NULL)
3957c478bd9Sstevel@tonic-gate 		return (NULL);
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	return (termio_accelstrings[(int)(acc - termio_accelkeys)]);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate static ssize_t
termio_read(mdb_io_t * io,void * buf,size_t nbytes)4017c478bd9Sstevel@tonic-gate termio_read(mdb_io_t *io, void *buf, size_t nbytes)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	mdb_bool_t esc = FALSE, pad = FALSE;
4067c478bd9Sstevel@tonic-gate 	ssize_t rlen = 0;
407892f67e4SJoshua M. Clulow 	int c, fkey = 0;
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	const char *s;
4107c478bd9Sstevel@tonic-gate 	size_t len;
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	if (io->io_next != NULL)
4137c478bd9Sstevel@tonic-gate 		return (IOP_READ(io->io_next, buf, nbytes));
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	td->tio_rti_on = TRUE;
4167c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCSETSW, &td->tio_rtios) == -1)
4177c478bd9Sstevel@tonic-gate 		warn("failed to set terminal attributes");
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate 	if (nbytes == 1) {
4207c478bd9Sstevel@tonic-gate 		if ((c = mdb_iob_getc(td->tio_in)) == EOF)
4217c478bd9Sstevel@tonic-gate 			goto out;
4227c478bd9Sstevel@tonic-gate 
4237c478bd9Sstevel@tonic-gate 		*((uchar_t *)buf) = (uchar_t)c;
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 		rlen = 1;
4267c478bd9Sstevel@tonic-gate 		goto out;
4277c478bd9Sstevel@tonic-gate 	}
4287c478bd9Sstevel@tonic-gate 
4293b6e0a59SMatt Amdur 	if (td->tio_flags & TIO_TAB)
4303b6e0a59SMatt Amdur 		termio_redraw(td);
4313b6e0a59SMatt Amdur 	else
4323b6e0a59SMatt Amdur 		termio_prompt(td);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	/*
4357c478bd9Sstevel@tonic-gate 	 * We need to redraw the entire command-line and restart our read loop
4367c478bd9Sstevel@tonic-gate 	 * in the event of a SIGWINCH or resume following SIGTSTP (SIGCONT).
4377c478bd9Sstevel@tonic-gate 	 */
4387c478bd9Sstevel@tonic-gate 	if (sigsetjmp(td->tio_env, 1) != 0) {
4397c478bd9Sstevel@tonic-gate 		td->tio_active = FALSE;
4407c478bd9Sstevel@tonic-gate 		td->tio_x = td->tio_y = 0;
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 		len = td->tio_cmdbuf.cmd_buflen + td->tio_promptlen;
4437c478bd9Sstevel@tonic-gate 		td->tio_max_x = len % td->tio_cols;
4447c478bd9Sstevel@tonic-gate 		td->tio_max_y = len / td->tio_cols;
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		esc = pad = FALSE;
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cr.at_str, 1);
4497c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
4507c478bd9Sstevel@tonic-gate 		termio_redraw(td);
4517c478bd9Sstevel@tonic-gate 	}
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	/*
4547c478bd9Sstevel@tonic-gate 	 * Since we're about to start the read loop, we know our linked iob
4557c478bd9Sstevel@tonic-gate 	 * is quiescent. We can now safely resize it to the latest term size.
4567c478bd9Sstevel@tonic-gate 	 */
4577c478bd9Sstevel@tonic-gate 	if (td->tio_link != NULL)
4587c478bd9Sstevel@tonic-gate 		mdb_iob_resize(td->tio_link, td->tio_rows, td->tio_cols);
4597c478bd9Sstevel@tonic-gate 
4607c478bd9Sstevel@tonic-gate 	td->tio_active = TRUE;
4617c478bd9Sstevel@tonic-gate 
4623b6e0a59SMatt Amdur 	/*
4633b6e0a59SMatt Amdur 	 * We may have had some error while in tab completion mode which sent us
4643b6e0a59SMatt Amdur 	 * longjmping all over the place. If that's the case, come back here and
4653b6e0a59SMatt Amdur 	 * make sure the flag is off.
4663b6e0a59SMatt Amdur 	 */
4673b6e0a59SMatt Amdur 	td->tio_flags &= ~TIO_TAB;
4683b6e0a59SMatt Amdur 
4697c478bd9Sstevel@tonic-gate 	do {
4707c478bd9Sstevel@tonic-gate char_loop:
4717c478bd9Sstevel@tonic-gate 		if ((c = mdb_iob_getc(td->tio_in)) == EOF) {
4727c478bd9Sstevel@tonic-gate 			td->tio_active = FALSE;
4737c478bd9Sstevel@tonic-gate 			goto out;
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		if (c == KEY_ESC && esc == FALSE) {
4777c478bd9Sstevel@tonic-gate 			esc = TRUE;
4787c478bd9Sstevel@tonic-gate 			goto char_loop;
4797c478bd9Sstevel@tonic-gate 		}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		if (esc) {
4827c478bd9Sstevel@tonic-gate 			esc = FALSE;
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 			if (c == '[') {
4857c478bd9Sstevel@tonic-gate 				pad++;
4867c478bd9Sstevel@tonic-gate 				goto char_loop;
4877c478bd9Sstevel@tonic-gate 			}
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 			c = META(c);
4907c478bd9Sstevel@tonic-gate 		}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 		if (pad) {
4937c478bd9Sstevel@tonic-gate 			pad = FALSE;
494892f67e4SJoshua M. Clulow 
495892f67e4SJoshua M. Clulow 			if ((fkey = FKEY(c)) != 0) {
496892f67e4SJoshua M. Clulow 				/*
497892f67e4SJoshua M. Clulow 				 * Some terminals send a multibyte control
498892f67e4SJoshua M. Clulow 				 * sequence for particular function keys.
499892f67e4SJoshua M. Clulow 				 * These sequences are of the form:
500892f67e4SJoshua M. Clulow 				 *
501892f67e4SJoshua M. Clulow 				 *	ESC [ n ~
502892f67e4SJoshua M. Clulow 				 *
503892f67e4SJoshua M. Clulow 				 * where "n" is a numeric character from
504892f67e4SJoshua M. Clulow 				 * '0' to '9'.
505892f67e4SJoshua M. Clulow 				 */
506892f67e4SJoshua M. Clulow 				goto char_loop;
507892f67e4SJoshua M. Clulow 			}
508892f67e4SJoshua M. Clulow 
509892f67e4SJoshua M. Clulow 			if ((c = KPAD(c)) == 0) {
510892f67e4SJoshua M. Clulow 				/*
511892f67e4SJoshua M. Clulow 				 * This was not a valid keypad control
512892f67e4SJoshua M. Clulow 				 * sequence.
513892f67e4SJoshua M. Clulow 				 */
514892f67e4SJoshua M. Clulow 				goto char_loop;
515892f67e4SJoshua M. Clulow 			}
516892f67e4SJoshua M. Clulow 		}
517892f67e4SJoshua M. Clulow 
518892f67e4SJoshua M. Clulow 		if (fkey != 0) {
519892f67e4SJoshua M. Clulow 			if (c == '~') {
520892f67e4SJoshua M. Clulow 				/*
521892f67e4SJoshua M. Clulow 				 * This is a valid special function key
522892f67e4SJoshua M. Clulow 				 * sequence.  Use the value we stashed
523892f67e4SJoshua M. Clulow 				 * earlier.
524892f67e4SJoshua M. Clulow 				 */
525892f67e4SJoshua M. Clulow 				c = fkey;
526892f67e4SJoshua M. Clulow 			}
527892f67e4SJoshua M. Clulow 
528892f67e4SJoshua M. Clulow 			fkey = 0;
5297c478bd9Sstevel@tonic-gate 		}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 		len = td->tio_cmdbuf.cmd_buflen + td->tio_promptlen;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		td->tio_max_x = len % td->tio_cols;
5347c478bd9Sstevel@tonic-gate 		td->tio_max_y = len / td->tio_cols;
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate 	} while ((s = (*td->tio_keymap[c])(td, c)) == NULL);
5377c478bd9Sstevel@tonic-gate 
5387c478bd9Sstevel@tonic-gate 	td->tio_active = FALSE;
5397c478bd9Sstevel@tonic-gate 	mdb_iob_nl(td->tio_out);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	if ((rlen = strlen(s)) >= nbytes - 1)
5427c478bd9Sstevel@tonic-gate 		rlen = nbytes - 1;
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	(void) strncpy(buf, s, rlen);
5457c478bd9Sstevel@tonic-gate 	((char *)buf)[rlen++] = '\n';
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate out:
5487c478bd9Sstevel@tonic-gate 	td->tio_rti_on = FALSE;
5497c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
5507c478bd9Sstevel@tonic-gate 		warn("failed to restore terminal attributes");
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	return (rlen);
5537c478bd9Sstevel@tonic-gate }
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate static ssize_t
termio_write(mdb_io_t * io,const void * buf,size_t nbytes)5567c478bd9Sstevel@tonic-gate termio_write(mdb_io_t *io, const void *buf, size_t nbytes)
5577c478bd9Sstevel@tonic-gate {
5587c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	if (io->io_next != NULL)
5617c478bd9Sstevel@tonic-gate 		return (IOP_WRITE(io->io_next, buf, nbytes));
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	return (IOP_WRITE(td->tio_out_io, buf, nbytes));
5647c478bd9Sstevel@tonic-gate }
5657c478bd9Sstevel@tonic-gate 
5667c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5677c478bd9Sstevel@tonic-gate static off64_t
termio_seek(mdb_io_t * io,off64_t offset,int whence)5687c478bd9Sstevel@tonic-gate termio_seek(mdb_io_t *io, off64_t offset, int whence)
5697c478bd9Sstevel@tonic-gate {
5707c478bd9Sstevel@tonic-gate 	return (set_errno(ENOTSUP));
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate static int
termio_ctl(mdb_io_t * io,int req,void * arg)5747c478bd9Sstevel@tonic-gate termio_ctl(mdb_io_t *io, int req, void *arg)
5757c478bd9Sstevel@tonic-gate {
5767c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	if (io->io_next != NULL)
5797c478bd9Sstevel@tonic-gate 		return (IOP_CTL(io->io_next, req, arg));
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (req == MDB_IOC_CTTY) {
5827c478bd9Sstevel@tonic-gate 		bcopy(&td->tio_ptios, &td->tio_ctios, sizeof (struct termios));
5837c478bd9Sstevel@tonic-gate 		return (0);
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	return (IOP_CTL(td->tio_in_io, req, arg));
5877c478bd9Sstevel@tonic-gate }
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate static void
termio_close(mdb_io_t * io)5907c478bd9Sstevel@tonic-gate termio_close(mdb_io_t *io)
5917c478bd9Sstevel@tonic-gate {
5927c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
5937c478bd9Sstevel@tonic-gate 
594*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGWINCH, MDB_SIG_DFL, NULL);
595*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_DFL, NULL);
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	termio_suspend_tty(td, &td->tio_ptios);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	if (td->tio_attrs)
6007c478bd9Sstevel@tonic-gate 		mdb_free(td->tio_attrs, td->tio_attrslen);
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 	mdb_cmdbuf_destroy(&td->tio_cmdbuf);
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 	mdb_iob_destroy(td->tio_out);
6057c478bd9Sstevel@tonic-gate 	mdb_iob_destroy(td->tio_in);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	mdb_free(td, sizeof (termio_data_t));
6087c478bd9Sstevel@tonic-gate }
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate static const char *
termio_name(mdb_io_t * io)6117c478bd9Sstevel@tonic-gate termio_name(mdb_io_t *io)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (io->io_next != NULL)
6167c478bd9Sstevel@tonic-gate 		return (IOP_NAME(io->io_next));
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	return (IOP_NAME(td->tio_in_io));
6197c478bd9Sstevel@tonic-gate }
6207c478bd9Sstevel@tonic-gate 
6217c478bd9Sstevel@tonic-gate static void
termio_link(mdb_io_t * io,mdb_iob_t * iob)6227c478bd9Sstevel@tonic-gate termio_link(mdb_io_t *io, mdb_iob_t *iob)
6237c478bd9Sstevel@tonic-gate {
6247c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (io->io_next == NULL) {
6277c478bd9Sstevel@tonic-gate 		mdb_iob_resize(iob, td->tio_rows, td->tio_cols);
6287c478bd9Sstevel@tonic-gate 		td->tio_link = iob;
6297c478bd9Sstevel@tonic-gate 	} else
6307c478bd9Sstevel@tonic-gate 		IOP_LINK(io->io_next, iob);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate static void
termio_unlink(mdb_io_t * io,mdb_iob_t * iob)6347c478bd9Sstevel@tonic-gate termio_unlink(mdb_io_t *io, mdb_iob_t *iob)
6357c478bd9Sstevel@tonic-gate {
6367c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
6377c478bd9Sstevel@tonic-gate 
6387c478bd9Sstevel@tonic-gate 	if (io->io_next == NULL) {
6397c478bd9Sstevel@tonic-gate 		if (td->tio_link == iob)
6407c478bd9Sstevel@tonic-gate 			td->tio_link = NULL;
6417c478bd9Sstevel@tonic-gate 	} else
6427c478bd9Sstevel@tonic-gate 		IOP_UNLINK(io->io_next, iob);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate static int
termio_setattr(mdb_io_t * io,int req,uint_t attrs)6467c478bd9Sstevel@tonic-gate termio_setattr(mdb_io_t *io, int req, uint_t attrs)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (io->io_next != NULL)
6517c478bd9Sstevel@tonic-gate 		return (IOP_SETATTR(io->io_next, req, attrs));
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if ((req != ATT_ON && req != ATT_OFF) || (attrs & ~ATT_ALL) != 0)
6547c478bd9Sstevel@tonic-gate 		return (set_errno(EINVAL));
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	if (req == ATT_ON) {
6577c478bd9Sstevel@tonic-gate 		if (attrs & ATT_STANDOUT)
6587c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_smso.at_str, 1);
6597c478bd9Sstevel@tonic-gate 		if (attrs & ATT_UNDERLINE)
6607c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_smul.at_str, 1);
6617c478bd9Sstevel@tonic-gate 		if (attrs & ATT_REVERSE)
6627c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_rev.at_str, 1);
6637c478bd9Sstevel@tonic-gate 		if (attrs & ATT_BOLD)
6647c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_bold.at_str, 1);
6657c478bd9Sstevel@tonic-gate 		if (attrs & ATT_DIM)
6667c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_dim.at_str, 1);
6677c478bd9Sstevel@tonic-gate 		if (attrs & ATT_ALTCHARSET)
6687c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_smacs.at_str, 1);
6697c478bd9Sstevel@tonic-gate 	} else {
6707c478bd9Sstevel@tonic-gate 		if (attrs & ATT_STANDOUT)
6717c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_rmso.at_str, 1);
6727c478bd9Sstevel@tonic-gate 		if (attrs & ATT_UNDERLINE)
6737c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_rmul.at_str, 1);
6747c478bd9Sstevel@tonic-gate 		if (attrs & ATT_ALTCHARSET)
6757c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_rmacs.at_str, 1);
6767c478bd9Sstevel@tonic-gate 		if (attrs & (ATT_REVERSE | ATT_BOLD | ATT_DIM))
6777c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_sgr0.at_str, 1);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
6817c478bd9Sstevel@tonic-gate 	return (0);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate /*
6857c478bd9Sstevel@tonic-gate  * Issue a warning message if the given warning flag is clear.  Then set the
6867c478bd9Sstevel@tonic-gate  * flag bit so that we do not issue multiple instances of the same warning.
6877c478bd9Sstevel@tonic-gate  */
6887c478bd9Sstevel@tonic-gate static void
termio_warn(termio_data_t * td,uint_t flag,const char * format,...)6897c478bd9Sstevel@tonic-gate termio_warn(termio_data_t *td, uint_t flag, const char *format, ...)
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	if (!(td->tio_flags & flag)) {
6927c478bd9Sstevel@tonic-gate 		va_list alist;
6937c478bd9Sstevel@tonic-gate 
6947c478bd9Sstevel@tonic-gate 		va_start(alist, format);
6957c478bd9Sstevel@tonic-gate 		vwarn(format, alist);
6967c478bd9Sstevel@tonic-gate 		va_end(alist);
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 		td->tio_flags |= flag;
6997c478bd9Sstevel@tonic-gate 	}
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*
7037c478bd9Sstevel@tonic-gate  * Restore the terminal to its previous state before relinquishing control of
7047c478bd9Sstevel@tonic-gate  * it to the shell (on a SIGTSTP) or the victim process (on a continue).  If
7057c478bd9Sstevel@tonic-gate  * we need to change the foreground process group, we must temporarily ignore
7067c478bd9Sstevel@tonic-gate  * SIGTTOU because TIOCSPGRP could trigger it.
7077c478bd9Sstevel@tonic-gate  */
7087c478bd9Sstevel@tonic-gate static void
termio_suspend_tty(termio_data_t * td,struct termios * iosp)7097c478bd9Sstevel@tonic-gate termio_suspend_tty(termio_data_t *td, struct termios *iosp)
7107c478bd9Sstevel@tonic-gate {
7117c478bd9Sstevel@tonic-gate 	if (td->tio_suspended++ != 0)
7127c478bd9Sstevel@tonic-gate 		return; /* already suspended; do not restore state */
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_XTERM)
7157c478bd9Sstevel@tonic-gate 		termio_tput(td, TI_DECRES(TI_COLENAB), 1);
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_USECUP)
7187c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_rmcup.at_str, 1);
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	termio_tput(td, td->tio_info.ti_sgr0.at_str, 1);
7217c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCSETSW, iosp) == -1)
7247c478bd9Sstevel@tonic-gate 		warn("failed to restore terminal attributes");
7257c478bd9Sstevel@tonic-gate 
7267c478bd9Sstevel@tonic-gate 	if (td->tio_opgid > 0 && td->tio_opgid != mdb.m_pgid) {
7277c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_CMDBUF, "fg pgid=%d\n", (int)td->tio_opgid);
728*30699046SRichard Lowe 		(void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_IGN, NULL);
7297c478bd9Sstevel@tonic-gate 		(void) termio_ctl(td->tio_io, TIOCSPGRP, &td->tio_opgid);
730*30699046SRichard Lowe 		(void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_DFL, NULL);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate }
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate /*
7357c478bd9Sstevel@tonic-gate  * Resume the debugger's terminal state.  We first save the existing terminal
7367c478bd9Sstevel@tonic-gate  * state so we can restore it later, and then install our own state.  We
7377c478bd9Sstevel@tonic-gate  * derive our state dynamically from the existing terminal state so that we
7387c478bd9Sstevel@tonic-gate  * always reflect the latest modifications made by the user with stty(1).
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate static void
termio_resume_tty(termio_data_t * td,struct termios * iosp)7417c478bd9Sstevel@tonic-gate termio_resume_tty(termio_data_t *td, struct termios *iosp)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	/*
7447c478bd9Sstevel@tonic-gate 	 * We use this table of bauds to convert the baud constant returned by
7457c478bd9Sstevel@tonic-gate 	 * the terminal code to a baud rate in characters per second.  The
7467c478bd9Sstevel@tonic-gate 	 * values are in the order of the B* speed defines in <sys/termios.h>.
7477c478bd9Sstevel@tonic-gate 	 * We then compute tio_usecpc (microseconds-per-char) in order to
7487c478bd9Sstevel@tonic-gate 	 * determine how many pad characters need to be issued at the current
7497c478bd9Sstevel@tonic-gate 	 * terminal speed to delay for a given number of microseconds.  For
7507c478bd9Sstevel@tonic-gate 	 * example, at 300 baud (B300 = 7), we look up baud[7] = 300, and then
7517c478bd9Sstevel@tonic-gate 	 * compute usecpc as MICROSEC / 300 = 3333 microseconds per character.
7527c478bd9Sstevel@tonic-gate 	 */
7537c478bd9Sstevel@tonic-gate 	static const uint_t baud[] = {
7547c478bd9Sstevel@tonic-gate 		0, 50, 75, 110, 134, 150, 200, 300, 600, 1200,
7557c478bd9Sstevel@tonic-gate 		1800, 2400, 4800, 9600, 19200, 38400, 57600,
756d9c3e05cSJoshua M. Clulow 		76800, 115200, 153600, 230400, 307200, 460800, 921600,
757d9c3e05cSJoshua M. Clulow 		1000000, 1152000, 1500000, 2000000, 2500000, 3000000,
758d9c3e05cSJoshua M. Clulow 		3500000, 4000000
7597c478bd9Sstevel@tonic-gate 	};
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	struct termios *ntios;
7627c478bd9Sstevel@tonic-gate 	struct winsize winsz;
7637c478bd9Sstevel@tonic-gate 	uint_t speed;
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	if (td->tio_suspended == 0)
7667c478bd9Sstevel@tonic-gate 		fail("termio_resume called without matching termio_suspend\n");
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	if (--td->tio_suspended != 0)
7697c478bd9Sstevel@tonic-gate 		return; /* nested suspends; do not resume yet */
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	td->tio_opgid = -1; /* set to invalid pgid in case TIOCPGRP fails */
7727c478bd9Sstevel@tonic-gate 	(void) termio_ctl(td->tio_io, TIOCGPGRP, &td->tio_opgid);
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	/*
7757c478bd9Sstevel@tonic-gate 	 * If the foreground process group does not include the debugger, reset
7767c478bd9Sstevel@tonic-gate 	 * the foreground process group so we are in control of the terminal.
7777c478bd9Sstevel@tonic-gate 	 * We temporarily ignore TTOU because TIOCSPGRP could trigger it.
7787c478bd9Sstevel@tonic-gate 	 */
7797c478bd9Sstevel@tonic-gate 	if (td->tio_opgid != mdb.m_pgid) {
780*30699046SRichard Lowe 		(void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_IGN, NULL);
7817c478bd9Sstevel@tonic-gate 		(void) termio_ctl(td->tio_io, TIOCSPGRP, &mdb.m_pgid);
782*30699046SRichard Lowe 		(void) mdb_signal_sethandler(SIGTTOU, MDB_SIG_DFL, NULL);
7837c478bd9Sstevel@tonic-gate 		mdb_dprintf(MDB_DBG_CMDBUF, "fg pgid=%d\n", (int)mdb.m_pgid);
7847c478bd9Sstevel@tonic-gate 	}
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/*
7877c478bd9Sstevel@tonic-gate 	 * Read the current set of terminal attributes, and save them in iosp
7887c478bd9Sstevel@tonic-gate 	 * so we can restore them later.  Then derive rtios, dtios, and winsz.
7897c478bd9Sstevel@tonic-gate 	 */
7907c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCGETS, iosp) < 0)
7917c478bd9Sstevel@tonic-gate 		warn("failed to get terminal attributes");
7927c478bd9Sstevel@tonic-gate 
7937c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TIOCGWINSZ, &winsz) == 0) {
7947c478bd9Sstevel@tonic-gate 		if (winsz.ws_row != 0)
7957c478bd9Sstevel@tonic-gate 			td->tio_rows = (size_t)winsz.ws_row;
7967c478bd9Sstevel@tonic-gate 		if (winsz.ws_col != 0)
7977c478bd9Sstevel@tonic-gate 			td->tio_cols = (size_t)winsz.ws_col;
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	mdb_iob_resize(td->tio_out, td->tio_rows, td->tio_cols);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	td->tio_intr = td->tio_ptios.c_cc[VINTR];
8037c478bd9Sstevel@tonic-gate 	td->tio_quit = td->tio_ptios.c_cc[VQUIT];
8047c478bd9Sstevel@tonic-gate 	td->tio_erase = td->tio_ptios.c_cc[VERASE];
8057c478bd9Sstevel@tonic-gate 	td->tio_werase = td->tio_ptios.c_cc[VWERASE];
8067c478bd9Sstevel@tonic-gate 	td->tio_kill = td->tio_ptios.c_cc[VKILL];
8077c478bd9Sstevel@tonic-gate 	td->tio_eof = td->tio_ptios.c_cc[VEOF];
8087c478bd9Sstevel@tonic-gate 	td->tio_susp = td->tio_ptios.c_cc[VSUSP];
8097c478bd9Sstevel@tonic-gate 
8107c478bd9Sstevel@tonic-gate 	bcopy(&td->tio_ptios, &td->tio_rtios, sizeof (struct termios));
8117c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_iflag &= ~(ISTRIP | INPCK | ICRNL | INLCR | IUCLC);
8127c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_oflag &= ~(OCRNL | ONLRET);
8137c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_oflag |= ONLCR;
8147c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_lflag &= ~(ISIG | ICANON | ECHO);
8157c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_cflag |= CS8;
8167c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_cc[VTIME] = 0;
8177c478bd9Sstevel@tonic-gate 	td->tio_rtios.c_cc[VMIN] = 1;
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate 	bcopy(&td->tio_ptios, &td->tio_dtios, sizeof (struct termios));
8207c478bd9Sstevel@tonic-gate 	td->tio_dtios.c_oflag &= ~(OCRNL | ONLRET);
8217c478bd9Sstevel@tonic-gate 	td->tio_dtios.c_oflag |= ONLCR;
8227c478bd9Sstevel@tonic-gate 	td->tio_dtios.c_lflag |= ISIG | ICANON | ECHO;
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	/*
8257c478bd9Sstevel@tonic-gate 	 * Select the appropriate modified settings to restore based on our
8267c478bd9Sstevel@tonic-gate 	 * current state, and then install them.
8277c478bd9Sstevel@tonic-gate 	 */
8287c478bd9Sstevel@tonic-gate 	if (td->tio_rti_on)
8297c478bd9Sstevel@tonic-gate 		ntios = &td->tio_rtios;
8307c478bd9Sstevel@tonic-gate 	else
8317c478bd9Sstevel@tonic-gate 		ntios = &td->tio_dtios;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCSETSW, ntios) < 0)
8347c478bd9Sstevel@tonic-gate 		warn("failed to reset terminal attributes");
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	/*
837bbf21555SRichard Lowe 	 * Compute the terminal speed as described in termio(4I), and then
8387c478bd9Sstevel@tonic-gate 	 * look up the corresponding microseconds-per-char in our table.
8397c478bd9Sstevel@tonic-gate 	 */
8407c478bd9Sstevel@tonic-gate 	if (ntios->c_cflag & CBAUDEXT)
8417c478bd9Sstevel@tonic-gate 		speed = (ntios->c_cflag & CBAUD) + CBAUD + 1;
8427c478bd9Sstevel@tonic-gate 	else
8437c478bd9Sstevel@tonic-gate 		speed = (ntios->c_cflag & CBAUD);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	if (speed >= sizeof (baud) / sizeof (baud[0])) {
8467c478bd9Sstevel@tonic-gate 		termio_warn(td, TIO_TTYWARN, "invalid speed %u -- assuming "
8477c478bd9Sstevel@tonic-gate 		    "9600 baud\n", speed);
8487c478bd9Sstevel@tonic-gate 		speed = B9600;
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	td->tio_baud = baud[speed];
8527c478bd9Sstevel@tonic-gate 	td->tio_usecpc = MICROSEC / td->tio_baud;
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_CMDBUF, "speed = %u baud (%u usec / char), "
8557c478bd9Sstevel@tonic-gate 	    "putp = %s\n", td->tio_baud, td->tio_usecpc,
8567c478bd9Sstevel@tonic-gate 	    td->tio_putp == &termio_puts ? "fast" : "slow");
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	/*
8597c478bd9Sstevel@tonic-gate 	 * Send the necessary terminal initialization sequences to enable
8607c478bd9Sstevel@tonic-gate 	 * enable cursor positioning.  Clear the screen afterward if possible.
8617c478bd9Sstevel@tonic-gate 	 */
8627c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_USECUP) {
8637c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_smcup.at_str, 1);
8647c478bd9Sstevel@tonic-gate 		if (td->tio_info.ti_clear.at_str) {
8657c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_clear.at_str, 1);
8667c478bd9Sstevel@tonic-gate 			td->tio_x = td->tio_y = 0;
8677c478bd9Sstevel@tonic-gate 		}
8687c478bd9Sstevel@tonic-gate 	}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	/*
8717c478bd9Sstevel@tonic-gate 	 * If the terminal is xterm-compatible, enable column mode switching.
8727c478bd9Sstevel@tonic-gate 	 * Save the previous value in the terminal so we can restore it.
8737c478bd9Sstevel@tonic-gate 	 */
8747c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_XTERM) {
8757c478bd9Sstevel@tonic-gate 		termio_tput(td, TI_DECSAV(TI_COLENAB), 1);
8767c478bd9Sstevel@tonic-gate 		termio_tput(td, TI_DECSET(TI_COLENAB), 1);
8777c478bd9Sstevel@tonic-gate 	}
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	termio_tput(td, td->tio_info.ti_cnorm.at_str, 1); /* cursor visible */
8807c478bd9Sstevel@tonic-gate 	termio_tput(td, td->tio_info.ti_enacs.at_str, 1); /* alt char set */
8817c478bd9Sstevel@tonic-gate 
882448027ebSBryan Cantrill 	/*
883448027ebSBryan Cantrill 	 * If the terminal is automargin-capable and we have an initialization
884448027ebSBryan Cantrill 	 * sequence to enable automargins, we must send it now.  Note that
885448027ebSBryan Cantrill 	 * we don't have a way of querying this mode and restoring it; if
886448027ebSBryan Cantrill 	 * we are fighting with (say) a target that is depending on automargin
887448027ebSBryan Cantrill 	 * being turned off, it will lose.
888448027ebSBryan Cantrill 	 */
889448027ebSBryan Cantrill 	if ((td->tio_flags & TIO_AUTOWRAP) &&
890448027ebSBryan Cantrill 	    td->tio_info.ti_smam.at_str != NULL) {
891448027ebSBryan Cantrill 		termio_tput(td, td->tio_info.ti_smam.at_str, 1);
892448027ebSBryan Cantrill 	}
893448027ebSBryan Cantrill 
8947c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate static void
termio_suspend(mdb_io_t * io)8987c478bd9Sstevel@tonic-gate termio_suspend(mdb_io_t *io)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
9017c478bd9Sstevel@tonic-gate 	termio_suspend_tty(td, &td->tio_ctios);
9027c478bd9Sstevel@tonic-gate }
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate static void
termio_resume(mdb_io_t * io)9057c478bd9Sstevel@tonic-gate termio_resume(mdb_io_t *io)
9067c478bd9Sstevel@tonic-gate {
9077c478bd9Sstevel@tonic-gate 	termio_data_t *td = io->io_data;
9087c478bd9Sstevel@tonic-gate 	termio_resume_tty(td, &td->tio_ctios);
9097c478bd9Sstevel@tonic-gate }
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate /*
9127c478bd9Sstevel@tonic-gate  * Delay for the specified number of microseconds by sending the pad character
9137c478bd9Sstevel@tonic-gate  * to the terminal.  We round up by half a frame and then divide by the usecs
9147c478bd9Sstevel@tonic-gate  * per character to determine the number of pad characters to send.
9157c478bd9Sstevel@tonic-gate  */
9167c478bd9Sstevel@tonic-gate static void
termio_delay(termio_data_t * td,uint_t usec)9177c478bd9Sstevel@tonic-gate termio_delay(termio_data_t *td, uint_t usec)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	char pad = td->tio_info.ti_pad.at_str[0];
9207c478bd9Sstevel@tonic-gate 	uint_t usecpc = td->tio_usecpc;
9217c478bd9Sstevel@tonic-gate 
9227c478bd9Sstevel@tonic-gate 	for (usec = (usec + usecpc / 2) / usecpc; usec != 0; usec--) {
9237c478bd9Sstevel@tonic-gate 		mdb_iob_putc(td->tio_out, pad);
9247c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
9257c478bd9Sstevel@tonic-gate 	}
9267c478bd9Sstevel@tonic-gate }
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate /*
929bbf21555SRichard Lowe  * Parse the terminfo(5) padding sequence "$<...>" and delay for the specified
9307c478bd9Sstevel@tonic-gate  * amount of time by sending pad characters to the terminal.
9317c478bd9Sstevel@tonic-gate  */
9327c478bd9Sstevel@tonic-gate static const char *
termio_pad(termio_data_t * td,const char * s,uint_t lines)9337c478bd9Sstevel@tonic-gate termio_pad(termio_data_t *td, const char *s, uint_t lines)
9347c478bd9Sstevel@tonic-gate {
9357c478bd9Sstevel@tonic-gate 	int xon = td->tio_info.ti_xon.at_val;
9367c478bd9Sstevel@tonic-gate 	int pb = td->tio_info.ti_pb.at_val;
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	const char *p = s;
9397c478bd9Sstevel@tonic-gate 	uint_t usec = 0;
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	/*
9427c478bd9Sstevel@tonic-gate 	 * The initial string is a number of milliseconds, followed by an
9437c478bd9Sstevel@tonic-gate 	 * optional decimal point and number of tenths of milliseconds.
9447c478bd9Sstevel@tonic-gate 	 * We convert this to microseconds for greater accuracy.  Only a single
9457c478bd9Sstevel@tonic-gate 	 * digit is permitted after the decimal point; we ignore any others.
9467c478bd9Sstevel@tonic-gate 	 */
9477c478bd9Sstevel@tonic-gate 	while (*p >= '0' && *p <= '9')
9487c478bd9Sstevel@tonic-gate 		usec = usec * 10 + *p++ - '0';
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	usec *= 1000; /* convert msecs to usecs */
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (*p == '.') {
9537c478bd9Sstevel@tonic-gate 		if (p[1] >= '0' && p[1] <= '9')
9547c478bd9Sstevel@tonic-gate 			usec += (p[1] - '0') * 100;
9557c478bd9Sstevel@tonic-gate 		for (p++; *p >= '0' && *p <= '9'; p++)
9567c478bd9Sstevel@tonic-gate 			continue;
9577c478bd9Sstevel@tonic-gate 	}
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 	/*
9607c478bd9Sstevel@tonic-gate 	 * Following the time delay specifier,
9617c478bd9Sstevel@tonic-gate 	 *
9627c478bd9Sstevel@tonic-gate 	 * 1. An optional "/" indicates that the delay should be done
9637c478bd9Sstevel@tonic-gate 	 *    regardless of the value of the terminal's xon property,
9647c478bd9Sstevel@tonic-gate 	 * 2. An optional "*" indicates that the delay is proportional to the
9657c478bd9Sstevel@tonic-gate 	 *    count of affected lines, and
9667c478bd9Sstevel@tonic-gate 	 * 3. A mandatory ">" terminates the sequence.
9677c478bd9Sstevel@tonic-gate 	 *
9687c478bd9Sstevel@tonic-gate 	 * If we encounter any other characters, we assume that we found "$<"
9697c478bd9Sstevel@tonic-gate 	 * accidentally embedded in another sequence, so we just output "$".
9707c478bd9Sstevel@tonic-gate 	 */
9717c478bd9Sstevel@tonic-gate 	for (;;) {
9727c478bd9Sstevel@tonic-gate 		switch (*p++) {
9737c478bd9Sstevel@tonic-gate 		case '/':
9747c478bd9Sstevel@tonic-gate 			xon = FALSE;
9757c478bd9Sstevel@tonic-gate 			continue;
9767c478bd9Sstevel@tonic-gate 		case '*':
9777c478bd9Sstevel@tonic-gate 			usec *= lines;
9787c478bd9Sstevel@tonic-gate 			continue;
9797c478bd9Sstevel@tonic-gate 		case '>':
9807c478bd9Sstevel@tonic-gate 			if (xon == FALSE && usec != 0 && td->tio_baud >= pb)
9817c478bd9Sstevel@tonic-gate 				termio_delay(td, usec);
9827c478bd9Sstevel@tonic-gate 			return (p);
9837c478bd9Sstevel@tonic-gate 		default:
9847c478bd9Sstevel@tonic-gate 			mdb_iob_putc(td->tio_out, *s);
9857c478bd9Sstevel@tonic-gate 			return (s + 1);
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate }
9897c478bd9Sstevel@tonic-gate 
9907c478bd9Sstevel@tonic-gate /*
9917c478bd9Sstevel@tonic-gate  * termio_tput() subroutine for terminals that require padding.  We look ahead
9927c478bd9Sstevel@tonic-gate  * for "$<>" sequences, and call termio_pad() to process them; all other chars
9937c478bd9Sstevel@tonic-gate  * are output directly to the underlying device and then flushed at the end.
9947c478bd9Sstevel@tonic-gate  */
9957c478bd9Sstevel@tonic-gate static void
termio_putp(termio_data_t * td,const char * s,uint_t lines)9967c478bd9Sstevel@tonic-gate termio_putp(termio_data_t *td, const char *s, uint_t lines)
9977c478bd9Sstevel@tonic-gate {
9987c478bd9Sstevel@tonic-gate 	while (s[0] != '\0') {
9997c478bd9Sstevel@tonic-gate 		if (s[0] == '$' && s[1] == '<')
10007c478bd9Sstevel@tonic-gate 			s = termio_pad(td, s + 2, lines);
10017c478bd9Sstevel@tonic-gate 		else
10027c478bd9Sstevel@tonic-gate 			mdb_iob_putc(td->tio_out, *s++);
10037c478bd9Sstevel@tonic-gate 	}
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate  * termio_tput() subroutine for terminals that do not require padding.  We
10107c478bd9Sstevel@tonic-gate  * simply output the string to the underlying i/o buffer; we let the caller
10117c478bd9Sstevel@tonic-gate  * take care of flushing so that multiple sequences can be concatenated.
10127c478bd9Sstevel@tonic-gate  */
10137c478bd9Sstevel@tonic-gate /*ARGSUSED*/
10147c478bd9Sstevel@tonic-gate static void
termio_puts(termio_data_t * td,const char * s,uint_t lines)10157c478bd9Sstevel@tonic-gate termio_puts(termio_data_t *td, const char *s, uint_t lines)
10167c478bd9Sstevel@tonic-gate {
10177c478bd9Sstevel@tonic-gate 	mdb_iob_puts(td->tio_out, s);
10187c478bd9Sstevel@tonic-gate }
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate /*
10217c478bd9Sstevel@tonic-gate  * Print a padded escape sequence string to the terminal.  The caller specifies
10227c478bd9Sstevel@tonic-gate  * the string 's' and a count of the affected lines.  If the string contains an
1023bbf21555SRichard Lowe  * embedded delay sequence delimited by "$<>" (see terminfo(5)), appropriate
10247c478bd9Sstevel@tonic-gate  * padding will be included in the output.  We determine whether or not padding
10257c478bd9Sstevel@tonic-gate  * is required during initialization, and set tio_putp to the proper subroutine.
10267c478bd9Sstevel@tonic-gate  */
10277c478bd9Sstevel@tonic-gate static void
termio_tput(termio_data_t * td,const char * s,uint_t lines)10287c478bd9Sstevel@tonic-gate termio_tput(termio_data_t *td, const char *s, uint_t lines)
10297c478bd9Sstevel@tonic-gate {
10307c478bd9Sstevel@tonic-gate 	if (s != NULL)
10317c478bd9Sstevel@tonic-gate 		td->tio_putp(td, s, lines);
10327c478bd9Sstevel@tonic-gate }
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate static void
termio_addch(termio_data_t * td,char c,size_t width)10357c478bd9Sstevel@tonic-gate termio_addch(termio_data_t *td, char c, size_t width)
10367c478bd9Sstevel@tonic-gate {
10377c478bd9Sstevel@tonic-gate 	if (width == 1) {
10387c478bd9Sstevel@tonic-gate 		mdb_iob_putc(td->tio_out, c);
10397c478bd9Sstevel@tonic-gate 		td->tio_x++;
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 		if (td->tio_x >= td->tio_cols) {
10427c478bd9Sstevel@tonic-gate 			if (!(td->tio_flags & TIO_AUTOWRAP))
10437c478bd9Sstevel@tonic-gate 				termio_tput(td, td->tio_info.ti_nel.at_str, 1);
10447c478bd9Sstevel@tonic-gate 			td->tio_x = 0;
10457c478bd9Sstevel@tonic-gate 			td->tio_y++;
10467c478bd9Sstevel@tonic-gate 		}
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
10497c478bd9Sstevel@tonic-gate 	} else
10507c478bd9Sstevel@tonic-gate 		termio_redraw(td);
10517c478bd9Sstevel@tonic-gate }
10527c478bd9Sstevel@tonic-gate 
10537c478bd9Sstevel@tonic-gate static void
termio_insch(termio_data_t * td,char c,size_t width)10547c478bd9Sstevel@tonic-gate termio_insch(termio_data_t *td, char c, size_t width)
10557c478bd9Sstevel@tonic-gate {
10567c478bd9Sstevel@tonic-gate 	if (width == 1 && (td->tio_flags & TIO_INSERT) &&
10577c478bd9Sstevel@tonic-gate 	    td->tio_y == td->tio_max_y) {
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_smir.at_str, 1);
10607c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_ich1.at_str, 1);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		mdb_iob_putc(td->tio_out, c);
10637c478bd9Sstevel@tonic-gate 		td->tio_x++;
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_ip.at_str, 1);
10667c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_rmir.at_str, 1);
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		if (td->tio_x >= td->tio_cols) {
10697c478bd9Sstevel@tonic-gate 			if (!(td->tio_flags & TIO_AUTOWRAP))
10707c478bd9Sstevel@tonic-gate 				termio_tput(td, td->tio_info.ti_nel.at_str, 1);
10717c478bd9Sstevel@tonic-gate 			td->tio_x = 0;
10727c478bd9Sstevel@tonic-gate 			td->tio_y++;
10737c478bd9Sstevel@tonic-gate 		}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
10767c478bd9Sstevel@tonic-gate 	} else
10777c478bd9Sstevel@tonic-gate 		termio_redraw(td);
10787c478bd9Sstevel@tonic-gate }
10797c478bd9Sstevel@tonic-gate 
10807c478bd9Sstevel@tonic-gate static void
termio_mvcur(termio_data_t * td)10817c478bd9Sstevel@tonic-gate termio_mvcur(termio_data_t *td)
10827c478bd9Sstevel@tonic-gate {
10837c478bd9Sstevel@tonic-gate 	size_t tipos = td->tio_cmdbuf.cmd_bufidx + td->tio_promptlen;
10847c478bd9Sstevel@tonic-gate 	size_t dst_x = tipos % td->tio_cols;
10857c478bd9Sstevel@tonic-gate 	size_t dst_y = tipos / td->tio_cols;
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	const char *str;
10887c478bd9Sstevel@tonic-gate 	size_t cnt, i;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 	if (td->tio_y != dst_y) {
10917c478bd9Sstevel@tonic-gate 		if (td->tio_y < dst_y) {
10927c478bd9Sstevel@tonic-gate 			str = td->tio_info.ti_cud1.at_str;
10937c478bd9Sstevel@tonic-gate 			cnt = dst_y - td->tio_y;
10947c478bd9Sstevel@tonic-gate 			td->tio_x = 0; /* Note: cud1 moves cursor to column 0 */
10957c478bd9Sstevel@tonic-gate 		} else {
10967c478bd9Sstevel@tonic-gate 			str = td->tio_info.ti_cuu1.at_str;
10977c478bd9Sstevel@tonic-gate 			cnt = td->tio_y - dst_y;
10987c478bd9Sstevel@tonic-gate 		}
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 		for (i = 0; i < cnt; i++)
11017c478bd9Sstevel@tonic-gate 			termio_tput(td, str, 1);
11027c478bd9Sstevel@tonic-gate 
11037c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
11047c478bd9Sstevel@tonic-gate 		td->tio_y = dst_y;
11057c478bd9Sstevel@tonic-gate 	}
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 	if (td->tio_x != dst_x) {
11087c478bd9Sstevel@tonic-gate 		if (td->tio_x < dst_x) {
11097c478bd9Sstevel@tonic-gate 			str = td->tio_info.ti_cuf1.at_str;
11107c478bd9Sstevel@tonic-gate 			cnt = dst_x - td->tio_x;
11117c478bd9Sstevel@tonic-gate 		} else {
11127c478bd9Sstevel@tonic-gate 			str = td->tio_info.ti_cub1.at_str;
11137c478bd9Sstevel@tonic-gate 			cnt = td->tio_x - dst_x;
11147c478bd9Sstevel@tonic-gate 		}
11157c478bd9Sstevel@tonic-gate 
11167c478bd9Sstevel@tonic-gate 		for (i = 0; i < cnt; i++)
11177c478bd9Sstevel@tonic-gate 			termio_tput(td, str, 1);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
11207c478bd9Sstevel@tonic-gate 		td->tio_x = dst_x;
11217c478bd9Sstevel@tonic-gate 	}
11227c478bd9Sstevel@tonic-gate }
11237c478bd9Sstevel@tonic-gate 
11247c478bd9Sstevel@tonic-gate static void
termio_backleft(termio_data_t * td)11257c478bd9Sstevel@tonic-gate termio_backleft(termio_data_t *td)
11267c478bd9Sstevel@tonic-gate {
11277c478bd9Sstevel@tonic-gate 	size_t i;
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_BACKLEFT)
11307c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
11317c478bd9Sstevel@tonic-gate 	else {
11327c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cuu1.at_str, 1);
11337c478bd9Sstevel@tonic-gate 		for (i = 0; i < td->tio_cols - 1; i++)
11347c478bd9Sstevel@tonic-gate 			termio_tput(td, td->tio_info.ti_cuf1.at_str, 1);
11357c478bd9Sstevel@tonic-gate 	}
11367c478bd9Sstevel@tonic-gate }
11377c478bd9Sstevel@tonic-gate 
11387c478bd9Sstevel@tonic-gate static void
termio_bspch(termio_data_t * td)11397c478bd9Sstevel@tonic-gate termio_bspch(termio_data_t *td)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	if (td->tio_x == 0) {
1142448027ebSBryan Cantrill 		/*
1143448027ebSBryan Cantrill 		 * If TIO_LAZYWRAP is set, we are regrettably in one of two
1144448027ebSBryan Cantrill 		 * states that we cannot differentiate between:  the cursor is
1145448027ebSBryan Cantrill 		 * either on the right margin of the previous line (having not
1146448027ebSBryan Cantrill 		 * advanced due to the lazy wrap) _or_ the cursor is on the
1147448027ebSBryan Cantrill 		 * left margin of the current line because a wrap has already
1148448027ebSBryan Cantrill 		 * been induced due to prior activity.  Because these cases are
1149448027ebSBryan Cantrill 		 * impossible to differentiate, we force the latter case by
1150448027ebSBryan Cantrill 		 * emitting a space and then moving the cursor back.  If the
1151448027ebSBryan Cantrill 		 * wrap had not been induced, emitting this space will induce
1152448027ebSBryan Cantrill 		 * it -- and will assure that our termio_backleft() is the
1153448027ebSBryan Cantrill 		 * correct behavior with respect to the cursor.
1154448027ebSBryan Cantrill 		 */
1155448027ebSBryan Cantrill 		if (td->tio_flags & TIO_LAZYWRAP) {
1156448027ebSBryan Cantrill 			mdb_iob_putc(td->tio_out, ' ');
1157448027ebSBryan Cantrill 			termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
1158448027ebSBryan Cantrill 		}
1159448027ebSBryan Cantrill 
11607c478bd9Sstevel@tonic-gate 		termio_backleft(td);
11617c478bd9Sstevel@tonic-gate 		td->tio_x = td->tio_cols - 1;
11627c478bd9Sstevel@tonic-gate 		td->tio_y--;
11637c478bd9Sstevel@tonic-gate 	} else {
11647c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
11657c478bd9Sstevel@tonic-gate 		td->tio_x--;
11667c478bd9Sstevel@tonic-gate 	}
11677c478bd9Sstevel@tonic-gate 
11687c478bd9Sstevel@tonic-gate 	termio_delch(td);
11697c478bd9Sstevel@tonic-gate }
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate static void
termio_delch(termio_data_t * td)11727c478bd9Sstevel@tonic-gate termio_delch(termio_data_t *td)
11737c478bd9Sstevel@tonic-gate {
11747c478bd9Sstevel@tonic-gate 	mdb_iob_putc(td->tio_out, ' ');
11757c478bd9Sstevel@tonic-gate 
1176448027ebSBryan Cantrill 	if (td->tio_x == td->tio_cols - 1 && (td->tio_flags & TIO_AUTOWRAP)) {
1177448027ebSBryan Cantrill 		/*
1178448027ebSBryan Cantrill 		 * We just overwrote a space in the final column, so we know
1179448027ebSBryan Cantrill 		 * that we have autowrapped and we therefore definitely don't
1180448027ebSBryan Cantrill 		 * want to issue the ti_cub1.  If we have TIO_LAZYWRAP, we know
1181448027ebSBryan Cantrill 		 * that the cursor remains on the final column, and we want to
1182448027ebSBryan Cantrill 		 * do nothing -- but if TIO_LAZYWRAP isn't set, we have wrapped
1183448027ebSBryan Cantrill 		 * and we need to move the cursor back up and all the way to
1184448027ebSBryan Cantrill 		 * the right via termio_backleft().
1185448027ebSBryan Cantrill 		 */
1186448027ebSBryan Cantrill 		if (!(td->tio_flags & TIO_LAZYWRAP))
1187448027ebSBryan Cantrill 			termio_backleft(td);
1188448027ebSBryan Cantrill 	} else {
11897c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
1190448027ebSBryan Cantrill 	}
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
11937c478bd9Sstevel@tonic-gate }
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate static void
termio_clear(termio_data_t * td)11967c478bd9Sstevel@tonic-gate termio_clear(termio_data_t *td)
11977c478bd9Sstevel@tonic-gate {
11987c478bd9Sstevel@tonic-gate 	while (td->tio_x-- != 0)
11997c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cub1.at_str, 1);
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	while (td->tio_y < td->tio_max_y) {
12027c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cud1.at_str, 1);
12037c478bd9Sstevel@tonic-gate 		td->tio_y++;
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	while (td->tio_y-- != 0) {
12077c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_el.at_str, 1);
12087c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_cuu1.at_str, 1);
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 
12117c478bd9Sstevel@tonic-gate 	termio_tput(td, td->tio_info.ti_el.at_str, 1);
12127c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	termio_prompt(td);
12157c478bd9Sstevel@tonic-gate }
12167c478bd9Sstevel@tonic-gate 
12177c478bd9Sstevel@tonic-gate static void
termio_redraw(termio_data_t * td)12187c478bd9Sstevel@tonic-gate termio_redraw(termio_data_t *td)
12197c478bd9Sstevel@tonic-gate {
12207c478bd9Sstevel@tonic-gate 	const char *buf = td->tio_cmdbuf.cmd_buf;
12217c478bd9Sstevel@tonic-gate 	size_t len = td->tio_cmdbuf.cmd_buflen;
12227c478bd9Sstevel@tonic-gate 	size_t pos, n;
12237c478bd9Sstevel@tonic-gate 
12247c478bd9Sstevel@tonic-gate 	termio_clear(td);
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if (len == 0)
12277c478bd9Sstevel@tonic-gate 		return; /* if the buffer is empty, we're done */
12287c478bd9Sstevel@tonic-gate 
12297c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_AUTOWRAP)
12307c478bd9Sstevel@tonic-gate 		mdb_iob_nputs(td->tio_out, buf, len);
12317c478bd9Sstevel@tonic-gate 	else {
12327c478bd9Sstevel@tonic-gate 		for (pos = td->tio_promptlen; len != 0; pos = 0) {
12337c478bd9Sstevel@tonic-gate 			n = MIN(td->tio_cols - pos, len);
12347c478bd9Sstevel@tonic-gate 			mdb_iob_nputs(td->tio_out, buf, n);
12357c478bd9Sstevel@tonic-gate 			buf += n;
12367c478bd9Sstevel@tonic-gate 			len -= n;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 			if (pos + n == td->tio_cols)
12397c478bd9Sstevel@tonic-gate 				termio_tput(td, td->tio_info.ti_nel.at_str, 1);
12407c478bd9Sstevel@tonic-gate 		}
12417c478bd9Sstevel@tonic-gate 	}
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	pos = td->tio_promptlen + td->tio_cmdbuf.cmd_buflen;
12447c478bd9Sstevel@tonic-gate 	td->tio_x = pos % td->tio_cols;
12457c478bd9Sstevel@tonic-gate 	td->tio_y = pos / td->tio_cols;
12467c478bd9Sstevel@tonic-gate 
12477c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
12487c478bd9Sstevel@tonic-gate 	termio_mvcur(td);
12497c478bd9Sstevel@tonic-gate }
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate static void
termio_prompt(termio_data_t * td)12527c478bd9Sstevel@tonic-gate termio_prompt(termio_data_t *td)
12537c478bd9Sstevel@tonic-gate {
12547c478bd9Sstevel@tonic-gate 	mdb_callb_fire(MDB_CALLB_PROMPT);
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	/*
12577c478bd9Sstevel@tonic-gate 	 * Findhist (^R) overrides the displayed prompt.  We should only update
12587c478bd9Sstevel@tonic-gate 	 * the main prompt (which may have been changed by the callback) if
12597c478bd9Sstevel@tonic-gate 	 * findhist isn't active.
12607c478bd9Sstevel@tonic-gate 	 */
12617c478bd9Sstevel@tonic-gate 	if (!(td->tio_flags & TIO_FINDHIST)) {
12627c478bd9Sstevel@tonic-gate 		td->tio_prompt = mdb.m_prompt;
12637c478bd9Sstevel@tonic-gate 		td->tio_promptlen = mdb.m_promptlen;
12647c478bd9Sstevel@tonic-gate 	}
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 	mdb_iob_puts(td->tio_out, td->tio_prompt);
12677c478bd9Sstevel@tonic-gate 	mdb_iob_flush(td->tio_out);
12687c478bd9Sstevel@tonic-gate 
12697c478bd9Sstevel@tonic-gate 	td->tio_x = td->tio_promptlen;
12707c478bd9Sstevel@tonic-gate 	td->tio_y = 0;
12717c478bd9Sstevel@tonic-gate }
12727c478bd9Sstevel@tonic-gate 
12737c478bd9Sstevel@tonic-gate /*
12747c478bd9Sstevel@tonic-gate  * For debugging purposes, iterate over the table of attributes and output them
12757c478bd9Sstevel@tonic-gate  * in human readable form for verification.
12767c478bd9Sstevel@tonic-gate  */
12777c478bd9Sstevel@tonic-gate static void
termio_dump(termio_data_t * td,const termio_attr_t * ta)12787c478bd9Sstevel@tonic-gate termio_dump(termio_data_t *td, const termio_attr_t *ta)
12797c478bd9Sstevel@tonic-gate {
12807c478bd9Sstevel@tonic-gate 	char *str;
12817c478bd9Sstevel@tonic-gate 
12827c478bd9Sstevel@tonic-gate 	for (; ta->ta_name != NULL; ta++) {
12837c478bd9Sstevel@tonic-gate 		switch (ta->ta_type) {
12847c478bd9Sstevel@tonic-gate 		case TIO_ATTR_REQSTR:
12857c478bd9Sstevel@tonic-gate 		case TIO_ATTR_STR:
12867c478bd9Sstevel@tonic-gate 			if (ta->ta_valp->at_str != NULL) {
12877c478bd9Sstevel@tonic-gate 				str = strchr2esc(ta->ta_valp->at_str,
12887c478bd9Sstevel@tonic-gate 				    strlen(ta->ta_valp->at_str));
12897c478bd9Sstevel@tonic-gate 				mdb_dprintf(MDB_DBG_CMDBUF, "%s = \"%s\"\n",
12907c478bd9Sstevel@tonic-gate 				    ta->ta_name, str);
12917c478bd9Sstevel@tonic-gate 				strfree(str);
12927c478bd9Sstevel@tonic-gate 			} else {
12937c478bd9Sstevel@tonic-gate 				mdb_dprintf(MDB_DBG_CMDBUF, "%s = <NULL>\n",
12947c478bd9Sstevel@tonic-gate 				    ta->ta_name);
12957c478bd9Sstevel@tonic-gate 			}
12967c478bd9Sstevel@tonic-gate 			break;
12977c478bd9Sstevel@tonic-gate 		case TIO_ATTR_INT:
12987c478bd9Sstevel@tonic-gate 			mdb_dprintf(MDB_DBG_CMDBUF, "%s = %d\n",
12997c478bd9Sstevel@tonic-gate 			    ta->ta_name, ta->ta_valp->at_val);
13007c478bd9Sstevel@tonic-gate 			break;
13017c478bd9Sstevel@tonic-gate 		case TIO_ATTR_BOOL:
13027c478bd9Sstevel@tonic-gate 			mdb_dprintf(MDB_DBG_CMDBUF, "%s = %s\n", ta->ta_name,
13037c478bd9Sstevel@tonic-gate 			    ta->ta_valp->at_val ? "TRUE" : "FALSE");
13047c478bd9Sstevel@tonic-gate 			break;
13057c478bd9Sstevel@tonic-gate 		}
13067c478bd9Sstevel@tonic-gate 	}
13077c478bd9Sstevel@tonic-gate 
13087c478bd9Sstevel@tonic-gate 	mdb_dprintf(MDB_DBG_CMDBUF, "tio_flags = <%#b>\n",
13097c478bd9Sstevel@tonic-gate 	    td->tio_flags, tio_flag_masks);
13107c478bd9Sstevel@tonic-gate }
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate static int
termio_setup_attrs(termio_data_t * td,const char * name)13137c478bd9Sstevel@tonic-gate termio_setup_attrs(termio_data_t *td, const char *name)
13147c478bd9Sstevel@tonic-gate {
13157c478bd9Sstevel@tonic-gate 	const termio_attr_t *ta;
13167c478bd9Sstevel@tonic-gate 	const char *str;
13177c478bd9Sstevel@tonic-gate 	size_t nbytes;
13187c478bd9Sstevel@tonic-gate 	char *bufp;
13197c478bd9Sstevel@tonic-gate 
13207c478bd9Sstevel@tonic-gate 	int need_padding = 0;
13217c478bd9Sstevel@tonic-gate 	int i;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	/*
13247c478bd9Sstevel@tonic-gate 	 * Load terminal attributes:
13257c478bd9Sstevel@tonic-gate 	 */
13267c478bd9Sstevel@tonic-gate 	for (nbytes = 0, ta = &termio_attrs[0]; ta->ta_name != NULL; ta++) {
13277c478bd9Sstevel@tonic-gate 		switch (ta->ta_type) {
13287c478bd9Sstevel@tonic-gate 		case TIO_ATTR_REQSTR:
13297c478bd9Sstevel@tonic-gate 		case TIO_ATTR_STR:
13307c478bd9Sstevel@tonic-gate 			str = tigetstr(ta->ta_name);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 			if (str == (const char *)-1) {
13337c478bd9Sstevel@tonic-gate 				termio_warn(td, TIO_CAPWARN,
13347c478bd9Sstevel@tonic-gate 				    "terminal capability '%s' is not of type "
13357c478bd9Sstevel@tonic-gate 				    "string as expected\n", ta->ta_name);
13367c478bd9Sstevel@tonic-gate 				return (0);
13377c478bd9Sstevel@tonic-gate 			}
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 			if (str != NULL)
13407c478bd9Sstevel@tonic-gate 				nbytes += strlen(str) + 1;
13417c478bd9Sstevel@tonic-gate 			else if (ta->ta_type == TIO_ATTR_REQSTR) {
13427c478bd9Sstevel@tonic-gate 				termio_warn(td, TIO_CAPWARN,
13437c478bd9Sstevel@tonic-gate 				    "terminal capability '%s' is not "
13447c478bd9Sstevel@tonic-gate 				    "available\n", ta->ta_name);
13457c478bd9Sstevel@tonic-gate 				return (0);
13467c478bd9Sstevel@tonic-gate 			}
13477c478bd9Sstevel@tonic-gate 			break;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 		case TIO_ATTR_BOOL:
13507c478bd9Sstevel@tonic-gate 			if (tigetflag(ta->ta_name) == -1) {
13517c478bd9Sstevel@tonic-gate 				termio_warn(td, TIO_CAPWARN,
13527c478bd9Sstevel@tonic-gate 				    "terminal capability '%s' is not of type "
13537c478bd9Sstevel@tonic-gate 				    "boolean as expected\n", ta->ta_name);
13547c478bd9Sstevel@tonic-gate 				return (0);
13557c478bd9Sstevel@tonic-gate 			}
13567c478bd9Sstevel@tonic-gate 			break;
13577c478bd9Sstevel@tonic-gate 
13587c478bd9Sstevel@tonic-gate 		case TIO_ATTR_INT:
13597c478bd9Sstevel@tonic-gate 			if (tigetnum(ta->ta_name) == -2) {
13607c478bd9Sstevel@tonic-gate 				termio_warn(td, TIO_CAPWARN,
13617c478bd9Sstevel@tonic-gate 				    "terminal capability '%s' is not of type "
13627c478bd9Sstevel@tonic-gate 				    "integer as expected\n", ta->ta_name);
13637c478bd9Sstevel@tonic-gate 				return (0);
13647c478bd9Sstevel@tonic-gate 			}
13657c478bd9Sstevel@tonic-gate 			break;
13667c478bd9Sstevel@tonic-gate 		}
13677c478bd9Sstevel@tonic-gate 	}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	if (nbytes != 0)
13707c478bd9Sstevel@tonic-gate 		td->tio_attrs = mdb_alloc(nbytes, UM_SLEEP);
13717c478bd9Sstevel@tonic-gate 	else
13727c478bd9Sstevel@tonic-gate 		td->tio_attrs = NULL;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	td->tio_attrslen = nbytes;
13757c478bd9Sstevel@tonic-gate 	bufp = td->tio_attrs;
13767c478bd9Sstevel@tonic-gate 
13777c478bd9Sstevel@tonic-gate 	/*
13787c478bd9Sstevel@tonic-gate 	 * Now make another pass through the terminal attributes and load the
13797c478bd9Sstevel@tonic-gate 	 * actual pointers into our static data structure:
13807c478bd9Sstevel@tonic-gate 	 */
13817c478bd9Sstevel@tonic-gate 	for (ta = &termio_attrs[0]; ta->ta_name != NULL; ta++) {
13827c478bd9Sstevel@tonic-gate 		switch (ta->ta_type) {
13837c478bd9Sstevel@tonic-gate 		case TIO_ATTR_REQSTR:
13847c478bd9Sstevel@tonic-gate 		case TIO_ATTR_STR:
13857c478bd9Sstevel@tonic-gate 			if ((str = tigetstr(ta->ta_name)) != NULL) {
13867c478bd9Sstevel@tonic-gate 				/*
13877c478bd9Sstevel@tonic-gate 				 * Copy the result string into our contiguous
13887c478bd9Sstevel@tonic-gate 				 * buffer, and store a pointer to it in at_str.
13897c478bd9Sstevel@tonic-gate 				 */
13907c478bd9Sstevel@tonic-gate 				(void) strcpy(bufp, str);
13917c478bd9Sstevel@tonic-gate 				ta->ta_valp->at_str = bufp;
13927c478bd9Sstevel@tonic-gate 				bufp += strlen(str) + 1;
13937c478bd9Sstevel@tonic-gate 				/*
13947c478bd9Sstevel@tonic-gate 				 * Check the string for a "$<>" pad sequence;
13957c478bd9Sstevel@tonic-gate 				 * if none are found, we can optimize later.
13967c478bd9Sstevel@tonic-gate 				 */
13977c478bd9Sstevel@tonic-gate 				if ((str = strstr(ta->ta_valp->at_str,
13987c478bd9Sstevel@tonic-gate 				    "$<")) != NULL && strchr(str, '>') != NULL)
13997c478bd9Sstevel@tonic-gate 					need_padding++;
14007c478bd9Sstevel@tonic-gate 			} else {
14017c478bd9Sstevel@tonic-gate 				ta->ta_valp->at_str = NULL;
14027c478bd9Sstevel@tonic-gate 			}
14037c478bd9Sstevel@tonic-gate 			break;
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		case TIO_ATTR_BOOL:
14067c478bd9Sstevel@tonic-gate 			ta->ta_valp->at_val = tigetflag(ta->ta_name);
14077c478bd9Sstevel@tonic-gate 			break;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 		case TIO_ATTR_INT:
14107c478bd9Sstevel@tonic-gate 			ta->ta_valp->at_val = tigetnum(ta->ta_name);
14117c478bd9Sstevel@tonic-gate 			break;
14127c478bd9Sstevel@tonic-gate 		}
14137c478bd9Sstevel@tonic-gate 	}
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate 	/*
14167c478bd9Sstevel@tonic-gate 	 * Copy attribute pointers from temporary struct into td->tio_info:
14177c478bd9Sstevel@tonic-gate 	 */
14187c478bd9Sstevel@tonic-gate 	bcopy(&termio_info, &td->tio_info, sizeof (termio_info_t));
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	/*
14217c478bd9Sstevel@tonic-gate 	 * Initialize the terminal size based on the terminfo database.  If it
14227c478bd9Sstevel@tonic-gate 	 * does not have the relevant properties, fall back to the environment
14237c478bd9Sstevel@tonic-gate 	 * settings or to a hardcoded default.  These settings will only be
14247c478bd9Sstevel@tonic-gate 	 * used if we subsequently fail to derive the size with TIOCGWINSZ.
14257c478bd9Sstevel@tonic-gate 	 */
14267c478bd9Sstevel@tonic-gate 	td->tio_rows = MAX(td->tio_info.ti_lines.at_val, 0);
14277c478bd9Sstevel@tonic-gate 	td->tio_cols = MAX(td->tio_info.ti_cols.at_val, 0);
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	if (td->tio_rows == 0) {
14307c478bd9Sstevel@tonic-gate 		if ((str = getenv("LINES")) != NULL && strisnum(str) != 0 &&
14317c478bd9Sstevel@tonic-gate 		    (i = strtoi(str)) > 0)
14327c478bd9Sstevel@tonic-gate 			td->tio_rows = i;
14337c478bd9Sstevel@tonic-gate 		else
14347c478bd9Sstevel@tonic-gate 			td->tio_rows = TIO_DEFAULT_ROWS;
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	if (td->tio_cols == 0) {
14387c478bd9Sstevel@tonic-gate 		if ((str = getenv("COLUMNS")) != NULL && strisnum(str) != 0 &&
14397c478bd9Sstevel@tonic-gate 		    (i = strtoi(str)) > 0)
14407c478bd9Sstevel@tonic-gate 			td->tio_cols = i;
14417c478bd9Sstevel@tonic-gate 		else
14427c478bd9Sstevel@tonic-gate 			td->tio_cols = TIO_DEFAULT_COLS;
14437c478bd9Sstevel@tonic-gate 	}
14447c478bd9Sstevel@tonic-gate 
14457c478bd9Sstevel@tonic-gate 	td->tio_flags = 0;
14467c478bd9Sstevel@tonic-gate 
1447448027ebSBryan Cantrill 	/*
1448448027ebSBryan Cantrill 	 * We turn on TIO_AUTOWRAP if "am" (automargin) is set on the terminal.
1449448027ebSBryan Cantrill 	 * Previously, this check was too smart for its own good, turning
1450448027ebSBryan Cantrill 	 * TIO_AUTOWRAP on only when both "am" was set _and_ "xenl" was unset.
1451448027ebSBryan Cantrill 	 * "xenl" is one of the (infamous?) so-called "Xanthippe glitches",
1452448027ebSBryan Cantrill 	 * this one pertaining to the Concept 100's feature of not autowrapping
1453448027ebSBryan Cantrill 	 * if the autowrap-inducing character is a newline.  (That is, the
1454448027ebSBryan Cantrill 	 * newline was "eaten" in this case -- and "xenl" accordingly stands
1455448027ebSBryan Cantrill 	 * for "Xanthippe eat newline", which itself sounds like a command from
1456448027ebSBryan Cantrill 	 * an Infocom game about line discipline set in ancient Greece.) This
1457448027ebSBryan Cantrill 	 * (now removed) condition misunderstood the semantics of "xenl",
1458448027ebSBryan Cantrill 	 * apparently inferring that its presence denoted that the terminal
1459448027ebSBryan Cantrill 	 * could not autowrap at all.  In fact, "xenl" is commonly set, and
1460448027ebSBryan Cantrill 	 * denotes that the terminal will not autowrap on a newline -- a
1461448027ebSBryan Cantrill 	 * feature (nee glitch) that is not particularly relevant with respect
1462448027ebSBryan Cantrill 	 * to our input processing.  (Ironically, disabling TIO_AUTOWRAP in
1463448027ebSBryan Cantrill 	 * this case only results in correct-seeming output because of the
1464448027ebSBryan Cantrill 	 * presence of the feature, as the inserted newline to force the wrap
1465448027ebSBryan Cantrill 	 * isn't actually displayed; were it displayed, the input buffer would
1466448027ebSBryan Cantrill 	 * appear double-spaced.)  So with respect to "xenl" and autowrapping,
1467448027ebSBryan Cantrill 	 * the correct behavior is to ignore it entirely, and adopt the
1468448027ebSBryan Cantrill 	 * (simpler and less arcane) logic of setting TIO_AUTOWRAP if (and only
1469448027ebSBryan Cantrill 	 * if) "am" is set on the terminal.  This does not, however, mean that
1470448027ebSBryan Cantrill 	 * "xenl" is meaningless; see below...
1471448027ebSBryan Cantrill 	 */
1472448027ebSBryan Cantrill 	if (td->tio_info.ti_am.at_val)
14737c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_AUTOWRAP;
14747c478bd9Sstevel@tonic-gate 
1475448027ebSBryan Cantrill 	/*
1476448027ebSBryan Cantrill 	 * While "xenl" doesn't dictate our TIO_AUTOWRAP setting, it does have
1477448027ebSBryan Cantrill 	 * a subtle impact on the way we process input:  in addition to its
1478448027ebSBryan Cantrill 	 * eponymous behavior of eating newlines, "xenl" denotes a second,
1479bbf21555SRichard Lowe 	 * entirely orthogonal idiosyncracy.  As terminfo(5) tells it: "Those
1480448027ebSBryan Cantrill 	 * terminals whose cursor remains on the right-most column until
1481448027ebSBryan Cantrill 	 * another character has been received, rather than wrapping
1482448027ebSBryan Cantrill 	 * immediately upon receiving the right- most character, such as the
1483448027ebSBryan Cantrill 	 * VT100, should also indicate xenl."  So yes, "xenl" in fact has two
1484448027ebSBryan Cantrill 	 * entirely different meanings -- it is a glitch-within-a-glitch, in
1485448027ebSBryan Cantrill 	 * what one assumes (hopes?) to be an accident of history rather than a
1486448027ebSBryan Cantrill 	 * deliberate act of sabotage.  This second behavior is relevant to us
1487448027ebSBryan Cantrill 	 * because it affects the way we redraw the screen after a backspace in
1488448027ebSBryan Cantrill 	 * the left-most column.  We call this second behavior "lazy wrapping",
1489448027ebSBryan Cantrill 	 * and we set it if (and only if) "xenl" is set on the terminal.
1490448027ebSBryan Cantrill 	 */
1491448027ebSBryan Cantrill 	if (td->tio_info.ti_xenl.at_val)
1492448027ebSBryan Cantrill 		td->tio_flags |= TIO_LAZYWRAP;
1493448027ebSBryan Cantrill 
14947c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_bw.at_val)
14957c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_BACKLEFT;
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_smir.at_str != NULL ||
14987c478bd9Sstevel@tonic-gate 	    td->tio_info.ti_ich1.at_str != NULL)
14997c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_INSERT;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	if (mdb.m_flags & MDB_FL_USECUP)
15027c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_USECUP;
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	if (name != NULL && (strncmp(name, "xterm", 5) == 0 ||
15057c478bd9Sstevel@tonic-gate 	    strcmp(name, "dtterm") == 0))
15067c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_XTERM;
15077c478bd9Sstevel@tonic-gate 
15087c478bd9Sstevel@tonic-gate 	/*
15097c478bd9Sstevel@tonic-gate 	 * Optimizations for padding: (1) if no pad attribute is present, set
15107c478bd9Sstevel@tonic-gate 	 * its value to "\0" to avoid testing later; (2) if no pad sequences
15117c478bd9Sstevel@tonic-gate 	 * were found, force "npc" to TRUE so we pick the optimized tio_putp;
15127c478bd9Sstevel@tonic-gate 	 * (3) if the padding baud property is not present, reset it to zero
15137c478bd9Sstevel@tonic-gate 	 * since we need to compare it to an unsigned baud value.
15147c478bd9Sstevel@tonic-gate 	 */
15157c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_pad.at_str == NULL)
15167c478bd9Sstevel@tonic-gate 		td->tio_info.ti_pad.at_str = ""; /* \0 is the pad char */
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate 	if (need_padding == 0)
15197c478bd9Sstevel@tonic-gate 		td->tio_info.ti_npc.at_val = TRUE;
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_npc.at_val)
15227c478bd9Sstevel@tonic-gate 		td->tio_putp = &termio_puts;
15237c478bd9Sstevel@tonic-gate 	else
15247c478bd9Sstevel@tonic-gate 		td->tio_putp = &termio_putp;
15257c478bd9Sstevel@tonic-gate 
15267c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_pb.at_val < 0)
15277c478bd9Sstevel@tonic-gate 		td->tio_info.ti_pb.at_val = 0;
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	/*
15307c478bd9Sstevel@tonic-gate 	 * If no newline capability is available, assume \r\n will work.  If no
15317c478bd9Sstevel@tonic-gate 	 * carriage return capability is available, assume \r will work.
15327c478bd9Sstevel@tonic-gate 	 */
15337c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_nel.at_str == NULL)
15347c478bd9Sstevel@tonic-gate 		td->tio_info.ti_nel.at_str = "\r\n";
15357c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_cr.at_str == NULL)
15367c478bd9Sstevel@tonic-gate 		td->tio_info.ti_cr.at_str = "\r";
15377c478bd9Sstevel@tonic-gate 
15387c478bd9Sstevel@tonic-gate 	return (1);
15397c478bd9Sstevel@tonic-gate }
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate mdb_io_t *
mdb_termio_create(const char * name,mdb_io_t * rio,mdb_io_t * wio)15427c478bd9Sstevel@tonic-gate mdb_termio_create(const char *name, mdb_io_t *rio, mdb_io_t *wio)
15437c478bd9Sstevel@tonic-gate {
15447c478bd9Sstevel@tonic-gate 	struct termios otios;
15457c478bd9Sstevel@tonic-gate 	termio_data_t *td;
15467c478bd9Sstevel@tonic-gate 	int rv, err, i;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	td = mdb_zalloc(sizeof (termio_data_t), UM_SLEEP);
15497c478bd9Sstevel@tonic-gate 	td->tio_io = mdb_alloc(sizeof (mdb_io_t), UM_SLEEP);
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	/*
15527c478bd9Sstevel@tonic-gate 	 * Save the original user settings before calling setupterm(), which
15537c478bd9Sstevel@tonic-gate 	 * cleverly changes them without telling us what it did or why.
15547c478bd9Sstevel@tonic-gate 	 */
15557c478bd9Sstevel@tonic-gate 	if (IOP_CTL(rio, TCGETS, &otios) == -1) {
15567c478bd9Sstevel@tonic-gate 		warn("failed to read terminal attributes for stdin");
15577c478bd9Sstevel@tonic-gate 		goto err;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	rv = setupterm((char *)name, IOP_CTL(rio, MDB_IOC_GETFD, NULL), &err);
15617c478bd9Sstevel@tonic-gate 	IOP_CTL(rio, TCSETSW, &otios); /* undo setupterm() stupidity */
15627c478bd9Sstevel@tonic-gate 
15637c478bd9Sstevel@tonic-gate 	if (rv == ERR) {
15647c478bd9Sstevel@tonic-gate 		if (err == 0)
15657c478bd9Sstevel@tonic-gate 			warn("no terminal data available for TERM=%s\n", name);
15667c478bd9Sstevel@tonic-gate 		else if (err == -1)
15677c478bd9Sstevel@tonic-gate 			warn("failed to locate terminfo database\n");
15687c478bd9Sstevel@tonic-gate 		else
15697c478bd9Sstevel@tonic-gate 			warn("failed to initialize terminal (err=%d)\n", err);
15707c478bd9Sstevel@tonic-gate 		goto err;
15717c478bd9Sstevel@tonic-gate 	}
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate 	if (!termio_setup_attrs(td, name))
15747c478bd9Sstevel@tonic-gate 		goto err;
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	/*
15777c478bd9Sstevel@tonic-gate 	 * Do not re-issue terminal capability warnings when mdb re-execs.
15787c478bd9Sstevel@tonic-gate 	 */
15797c478bd9Sstevel@tonic-gate 	if (mdb.m_flags & MDB_FL_EXEC)
15807c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_TTYWARN | TIO_CAPWARN;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	/*
15837c478bd9Sstevel@tonic-gate 	 * Initialize i/o structures and command-line buffer:
15847c478bd9Sstevel@tonic-gate 	 */
15857c478bd9Sstevel@tonic-gate 	td->tio_io->io_ops = &termio_ops;
15867c478bd9Sstevel@tonic-gate 	td->tio_io->io_data = td;
15877c478bd9Sstevel@tonic-gate 	td->tio_io->io_next = NULL;
15887c478bd9Sstevel@tonic-gate 	td->tio_io->io_refcnt = 0;
15897c478bd9Sstevel@tonic-gate 
15907c478bd9Sstevel@tonic-gate 	td->tio_in_io = rio;
15917c478bd9Sstevel@tonic-gate 	td->tio_in = mdb_iob_create(td->tio_in_io, MDB_IOB_RDONLY);
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	td->tio_out_io = wio;
15947c478bd9Sstevel@tonic-gate 	td->tio_out = mdb_iob_create(td->tio_out_io, MDB_IOB_WRONLY);
15957c478bd9Sstevel@tonic-gate 	mdb_iob_clrflags(td->tio_out, MDB_IOB_AUTOWRAP);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 	td->tio_link = NULL;
15987c478bd9Sstevel@tonic-gate 	mdb_cmdbuf_create(&td->tio_cmdbuf);
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	/*
16017c478bd9Sstevel@tonic-gate 	 * Fill in all the keymap entries with the insert function:
16027c478bd9Sstevel@tonic-gate 	 */
16037c478bd9Sstevel@tonic-gate 	for (i = 0; i < KEY_MAX; i++)
16047c478bd9Sstevel@tonic-gate 		td->tio_keymap[i] = termio_insert;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * Now override selected entries with editing functions:
16087c478bd9Sstevel@tonic-gate 	 */
16097c478bd9Sstevel@tonic-gate 	td->tio_keymap['\n'] = termio_accept;
16107c478bd9Sstevel@tonic-gate 	td->tio_keymap['\r'] = termio_accept;
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('f')] = termio_fwdchar;
16137c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('b')] = termio_backchar;
16147c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('t')] = termio_transpose;
16157c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('a')] = termio_home;
16167c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('e')] = termio_end;
16177c478bd9Sstevel@tonic-gate 	td->tio_keymap[META('f')] = termio_fwdword;
16187c478bd9Sstevel@tonic-gate 	td->tio_keymap[META('b')] = termio_backword;
16197c478bd9Sstevel@tonic-gate 	td->tio_keymap[META('d')] = termio_killfwdword;
16207c478bd9Sstevel@tonic-gate 	td->tio_keymap[META('\b')] = termio_killbackword;
16217c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('k')] = termio_kill;
16227c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('p')] = termio_prevhist;
16237c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('n')] = termio_nexthist;
16247c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('r')] = termio_findhist;
16257c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('l')] = termio_refresh;
16267c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('d')] = termio_delchar;
16277c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('?')] = termio_widescreen;
16287c478bd9Sstevel@tonic-gate 
1629892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('A')] = termio_prevhist;
1630892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('B')] = termio_nexthist;
1631892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('C')] = termio_fwdchar;
1632892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('D')] = termio_backchar;
1633892f67e4SJoshua M. Clulow 
1634892f67e4SJoshua M. Clulow 	/*
1635892f67e4SJoshua M. Clulow 	 * Many modern terminal emulators treat the "Home" and "End" keys on a
1636892f67e4SJoshua M. Clulow 	 * PC keyboard as cursor keys.  Some others use a multibyte function
1637892f67e4SJoshua M. Clulow 	 * key control sequence.  We handle both styles here:
1638892f67e4SJoshua M. Clulow 	 */
1639892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('H')] = termio_home;
1640892f67e4SJoshua M. Clulow 	td->tio_keymap[FKEY('1')] = termio_home;
1641892f67e4SJoshua M. Clulow 	td->tio_keymap[KPAD('F')] = termio_end;
1642892f67e4SJoshua M. Clulow 	td->tio_keymap[FKEY('4')] = termio_end;
16437c478bd9Sstevel@tonic-gate 
16447c478bd9Sstevel@tonic-gate 	/*
16457c478bd9Sstevel@tonic-gate 	 * We default both ASCII BS and DEL to termio_backspace for safety.  We
16467c478bd9Sstevel@tonic-gate 	 * want backspace to work whenever possible, regardless of whether or
16477c478bd9Sstevel@tonic-gate 	 * not we're able to ask the terminal for the specific character that
16487c478bd9Sstevel@tonic-gate 	 * it will use.  kmdb, for example, is not able to make this request,
16497c478bd9Sstevel@tonic-gate 	 * and must be prepared to accept both.
16507c478bd9Sstevel@tonic-gate 	 */
16517c478bd9Sstevel@tonic-gate 	td->tio_keymap[CTRL('h')] = termio_backspace;
16527c478bd9Sstevel@tonic-gate 	td->tio_keymap[KEY_DEL] = termio_backspace;
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 	/*
16557c478bd9Sstevel@tonic-gate 	 * Overrides for single-key accelerators
16567c478bd9Sstevel@tonic-gate 	 */
16577c478bd9Sstevel@tonic-gate 	td->tio_keymap['['] = termio_accel;
16587c478bd9Sstevel@tonic-gate 	td->tio_keymap[']'] = termio_accel;
16597c478bd9Sstevel@tonic-gate 
16603b6e0a59SMatt Amdur 	/*
16613b6e0a59SMatt Amdur 	 * Grab tabs
16623b6e0a59SMatt Amdur 	 */
16633b6e0a59SMatt Amdur 	td->tio_keymap['\t'] = termio_tab;
16643b6e0a59SMatt Amdur 
16657c478bd9Sstevel@tonic-gate 	td->tio_x = 0;
16667c478bd9Sstevel@tonic-gate 	td->tio_y = 0;
16677c478bd9Sstevel@tonic-gate 	td->tio_max_x = 0;
16687c478bd9Sstevel@tonic-gate 	td->tio_max_y = 0;
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	td->tio_active = FALSE;
16717c478bd9Sstevel@tonic-gate 	td->tio_rti_on = FALSE;
16727c478bd9Sstevel@tonic-gate 	td->tio_suspended = 1;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 	/*
16757c478bd9Sstevel@tonic-gate 	 * Perform a resume operation to complete our terminal initialization,
16767c478bd9Sstevel@tonic-gate 	 * and then adjust the keymap according to the terminal settings.
16777c478bd9Sstevel@tonic-gate 	 */
16787c478bd9Sstevel@tonic-gate 	termio_resume_tty(td, &td->tio_ptios);
16797c478bd9Sstevel@tonic-gate 	bcopy(&td->tio_ptios, &td->tio_ctios, sizeof (struct termios));
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_intr] = termio_intr;
16827c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_quit] = termio_quit;
16837c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_erase] = termio_backspace;
16847c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_werase] = termio_killbackword;
16857c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_kill] = termio_reset;
16867c478bd9Sstevel@tonic-gate 	td->tio_keymap[td->tio_susp] = termio_susp;
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGWINCH, termio_winch, td);
16897c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTSTP, termio_tstp, td);
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 	if (mdb.m_debug & MDB_DBG_CMDBUF)
16927c478bd9Sstevel@tonic-gate 		termio_dump(td, &termio_attrs[0]);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	return (td->tio_io);
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate err:
16977c478bd9Sstevel@tonic-gate 	mdb_free(td->tio_io, sizeof (mdb_io_t));
16987c478bd9Sstevel@tonic-gate 	mdb_free(td, sizeof (termio_data_t));
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	return (NULL);
17017c478bd9Sstevel@tonic-gate }
17027c478bd9Sstevel@tonic-gate 
17037c478bd9Sstevel@tonic-gate int
mdb_iob_isatty(mdb_iob_t * iob)17047c478bd9Sstevel@tonic-gate mdb_iob_isatty(mdb_iob_t *iob)
17057c478bd9Sstevel@tonic-gate {
17067c478bd9Sstevel@tonic-gate 	mdb_io_t *io;
17077c478bd9Sstevel@tonic-gate 
17087c478bd9Sstevel@tonic-gate 	if (iob->iob_flags & MDB_IOB_TTYLIKE)
17097c478bd9Sstevel@tonic-gate 		return (1);
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate 	for (io = iob->iob_iop; io != NULL; io = io->io_next) {
17127c478bd9Sstevel@tonic-gate 		if (io->io_ops == &termio_ops)
17137c478bd9Sstevel@tonic-gate 			return (1);
17147c478bd9Sstevel@tonic-gate 	}
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 	return (0);
17177c478bd9Sstevel@tonic-gate }
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate static const char *
termio_insert(termio_data_t * td,int c)17207c478bd9Sstevel@tonic-gate termio_insert(termio_data_t *td, int c)
17217c478bd9Sstevel@tonic-gate {
17227c478bd9Sstevel@tonic-gate 	size_t olen = td->tio_cmdbuf.cmd_buflen;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_insert(&td->tio_cmdbuf, c) == 0) {
17257c478bd9Sstevel@tonic-gate 		if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
17267c478bd9Sstevel@tonic-gate 			termio_addch(td, c, td->tio_cmdbuf.cmd_buflen - olen);
17277c478bd9Sstevel@tonic-gate 		else
17287c478bd9Sstevel@tonic-gate 			termio_insch(td, c, td->tio_cmdbuf.cmd_buflen - olen);
17297c478bd9Sstevel@tonic-gate 	}
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	return (NULL);
17327c478bd9Sstevel@tonic-gate }
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate static const char *
termio_accept(termio_data_t * td,int c)17357c478bd9Sstevel@tonic-gate termio_accept(termio_data_t *td, int c)
17367c478bd9Sstevel@tonic-gate {
17377c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_FINDHIST) {
17387c478bd9Sstevel@tonic-gate 		(void) mdb_cmdbuf_findhist(&td->tio_cmdbuf, c);
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 		td->tio_prompt = mdb.m_prompt;
17417c478bd9Sstevel@tonic-gate 		td->tio_promptlen = mdb.m_promptlen;
17427c478bd9Sstevel@tonic-gate 		td->tio_flags &= ~TIO_FINDHIST;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 		termio_redraw(td);
17457c478bd9Sstevel@tonic-gate 		return (NULL);
17467c478bd9Sstevel@tonic-gate 	}
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	/* Ensure that the cursor is at the end of the line */
17497c478bd9Sstevel@tonic-gate 	(void) termio_end(td, c);
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate 	return (mdb_cmdbuf_accept(&td->tio_cmdbuf));
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate static const char *
termio_backspace(termio_data_t * td,int c)17557c478bd9Sstevel@tonic-gate termio_backspace(termio_data_t *td, int c)
17567c478bd9Sstevel@tonic-gate {
17577c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_backspace(&td->tio_cmdbuf, c) == 0) {
17587c478bd9Sstevel@tonic-gate 		if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
17597c478bd9Sstevel@tonic-gate 			termio_bspch(td);
17607c478bd9Sstevel@tonic-gate 		else
17617c478bd9Sstevel@tonic-gate 			termio_redraw(td);
17627c478bd9Sstevel@tonic-gate 	}
17637c478bd9Sstevel@tonic-gate 
17647c478bd9Sstevel@tonic-gate 	return (NULL);
17657c478bd9Sstevel@tonic-gate }
17667c478bd9Sstevel@tonic-gate 
17673b6e0a59SMatt Amdur /*
17683b6e0a59SMatt Amdur  * This function may end up calling termio_read recursively as part of invoking
17693b6e0a59SMatt Amdur  * the mdb pager. To work around this fact, we need to go through and make sure
17703b6e0a59SMatt Amdur  * that we change the underlying terminal settings before and after this
17713b6e0a59SMatt Amdur  * function call. If we don't do this, we invoke the pager, and don't abort
17723b6e0a59SMatt Amdur  * (which will longjmp us elsewhere) we're going to return to the read loop with
17733b6e0a59SMatt Amdur  * the wrong termio settings.
17743b6e0a59SMatt Amdur  *
17753b6e0a59SMatt Amdur  * Furthermore, because of the fact that we're being invoked in a user context
17763b6e0a59SMatt Amdur  * that allows us to be interrupted, we need to actually allocate the memory
17773b6e0a59SMatt Amdur  * that we're using with GC so that it gets cleaned up in case of the pager
17783b6e0a59SMatt Amdur  * resetting us and never reaching the end.
17793b6e0a59SMatt Amdur  */
17803b6e0a59SMatt Amdur /*ARGSUSED*/
17813b6e0a59SMatt Amdur static const char *
termio_tab(termio_data_t * td,int c)17823b6e0a59SMatt Amdur termio_tab(termio_data_t *td, int c)
17833b6e0a59SMatt Amdur {
17843b6e0a59SMatt Amdur 	char *buf;
17853b6e0a59SMatt Amdur 	const char *result;
17863b6e0a59SMatt Amdur 	int nres;
17873b6e0a59SMatt Amdur 	mdb_tab_cookie_t *mtp;
17883b6e0a59SMatt Amdur 
17893b6e0a59SMatt Amdur 	if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
17903b6e0a59SMatt Amdur 		warn("failed to restore terminal attributes");
17913b6e0a59SMatt Amdur 
17923b6e0a59SMatt Amdur 	buf = mdb_alloc(td->tio_cmdbuf.cmd_bufidx + 1, UM_SLEEP | UM_GC);
17933b6e0a59SMatt Amdur 	(void) strncpy(buf, td->tio_cmdbuf.cmd_buf, td->tio_cmdbuf.cmd_bufidx);
17943b6e0a59SMatt Amdur 	buf[td->tio_cmdbuf.cmd_bufidx] = '\0';
17953b6e0a59SMatt Amdur 	td->tio_flags |= TIO_TAB;
17963b6e0a59SMatt Amdur 	mtp = mdb_tab_init();
17973b6e0a59SMatt Amdur 	nres = mdb_tab_command(mtp, buf);
17983b6e0a59SMatt Amdur 
17993b6e0a59SMatt Amdur 	if (nres == 0) {
18003b6e0a59SMatt Amdur 		result = NULL;
18013b6e0a59SMatt Amdur 	} else {
18023b6e0a59SMatt Amdur 		result = mdb_tab_match(mtp);
18033b6e0a59SMatt Amdur 		if (nres != 1) {
18043b6e0a59SMatt Amdur 			mdb_printf("\n");
18053b6e0a59SMatt Amdur 			mdb_tab_print(mtp);
18063b6e0a59SMatt Amdur 		}
18073b6e0a59SMatt Amdur 	}
18083b6e0a59SMatt Amdur 
18093b6e0a59SMatt Amdur 	if (result != NULL) {
18103b6e0a59SMatt Amdur 		int index = 0;
18113b6e0a59SMatt Amdur 
18123b6e0a59SMatt Amdur 		while (result[index] != '\0') {
18133b6e0a59SMatt Amdur 			(void) termio_insert(td, result[index]);
18143b6e0a59SMatt Amdur 			index++;
18153b6e0a59SMatt Amdur 		}
18163b6e0a59SMatt Amdur 	}
18173b6e0a59SMatt Amdur 
18183b6e0a59SMatt Amdur 	termio_redraw(td);
18193b6e0a59SMatt Amdur 	mdb_tab_fini(mtp);
18203b6e0a59SMatt Amdur 	td->tio_flags &= ~TIO_TAB;
18213b6e0a59SMatt Amdur 	if (termio_ctl(td->tio_io, TCSETSW, &td->tio_rtios) == -1)
18223b6e0a59SMatt Amdur 		warn("failed to set terminal attributes");
18233b6e0a59SMatt Amdur 
18243b6e0a59SMatt Amdur 
18253b6e0a59SMatt Amdur 	return (NULL);
18263b6e0a59SMatt Amdur }
18273b6e0a59SMatt Amdur 
18287c478bd9Sstevel@tonic-gate static const char *
termio_delchar(termio_data_t * td,int c)18297c478bd9Sstevel@tonic-gate termio_delchar(termio_data_t *td, int c)
18307c478bd9Sstevel@tonic-gate {
18317c478bd9Sstevel@tonic-gate 	if (!(mdb.m_flags & MDB_FL_IGNEOF) &&
18327c478bd9Sstevel@tonic-gate 	    mdb_cmdbuf_atend(&td->tio_cmdbuf) &&
18337c478bd9Sstevel@tonic-gate 	    mdb_cmdbuf_atstart(&td->tio_cmdbuf))
18347c478bd9Sstevel@tonic-gate 		return (termio_quit(td, c));
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_delchar(&td->tio_cmdbuf, c) == 0) {
18377c478bd9Sstevel@tonic-gate 		if (mdb_cmdbuf_atend(&td->tio_cmdbuf))
18387c478bd9Sstevel@tonic-gate 			termio_delch(td);
18397c478bd9Sstevel@tonic-gate 		else
18407c478bd9Sstevel@tonic-gate 			termio_redraw(td);
18417c478bd9Sstevel@tonic-gate 	}
18427c478bd9Sstevel@tonic-gate 
18437c478bd9Sstevel@tonic-gate 	return (NULL);
18447c478bd9Sstevel@tonic-gate }
18457c478bd9Sstevel@tonic-gate 
18467c478bd9Sstevel@tonic-gate static const char *
termio_fwdchar(termio_data_t * td,int c)18477c478bd9Sstevel@tonic-gate termio_fwdchar(termio_data_t *td, int c)
18487c478bd9Sstevel@tonic-gate {
18497c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_fwdchar(&td->tio_cmdbuf, c) == 0)
18507c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	return (NULL);
18537c478bd9Sstevel@tonic-gate }
18547c478bd9Sstevel@tonic-gate 
18557c478bd9Sstevel@tonic-gate static const char *
termio_backchar(termio_data_t * td,int c)18567c478bd9Sstevel@tonic-gate termio_backchar(termio_data_t *td, int c)
18577c478bd9Sstevel@tonic-gate {
18587c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_backchar(&td->tio_cmdbuf, c) == 0)
18597c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate 	return (NULL);
18627c478bd9Sstevel@tonic-gate }
18637c478bd9Sstevel@tonic-gate 
18647c478bd9Sstevel@tonic-gate static const char *
termio_transpose(termio_data_t * td,int c)18657c478bd9Sstevel@tonic-gate termio_transpose(termio_data_t *td, int c)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_transpose(&td->tio_cmdbuf, c) == 0)
18687c478bd9Sstevel@tonic-gate 		termio_redraw(td);
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate 	return (NULL);
18717c478bd9Sstevel@tonic-gate }
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate static const char *
termio_home(termio_data_t * td,int c)18747c478bd9Sstevel@tonic-gate termio_home(termio_data_t *td, int c)
18757c478bd9Sstevel@tonic-gate {
18767c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_home(&td->tio_cmdbuf, c) == 0)
18777c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	return (NULL);
18807c478bd9Sstevel@tonic-gate }
18817c478bd9Sstevel@tonic-gate 
18827c478bd9Sstevel@tonic-gate static const char *
termio_end(termio_data_t * td,int c)18837c478bd9Sstevel@tonic-gate termio_end(termio_data_t *td, int c)
18847c478bd9Sstevel@tonic-gate {
18857c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_end(&td->tio_cmdbuf, c) == 0)
18867c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	return (NULL);
18897c478bd9Sstevel@tonic-gate }
18907c478bd9Sstevel@tonic-gate 
18917c478bd9Sstevel@tonic-gate static const char *
termio_fwdword(termio_data_t * td,int c)18927c478bd9Sstevel@tonic-gate termio_fwdword(termio_data_t *td, int c)
18937c478bd9Sstevel@tonic-gate {
18947c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_fwdword(&td->tio_cmdbuf, c) == 0)
18957c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
18967c478bd9Sstevel@tonic-gate 
18977c478bd9Sstevel@tonic-gate 	return (NULL);
18987c478bd9Sstevel@tonic-gate }
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate static const char *
termio_backword(termio_data_t * td,int c)19017c478bd9Sstevel@tonic-gate termio_backword(termio_data_t *td, int c)
19027c478bd9Sstevel@tonic-gate {
19037c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_backword(&td->tio_cmdbuf, c) == 0)
19047c478bd9Sstevel@tonic-gate 		termio_mvcur(td);
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	return (NULL);
19077c478bd9Sstevel@tonic-gate }
19087c478bd9Sstevel@tonic-gate 
19097c478bd9Sstevel@tonic-gate static const char *
termio_kill(termio_data_t * td,int c)19107c478bd9Sstevel@tonic-gate termio_kill(termio_data_t *td, int c)
19117c478bd9Sstevel@tonic-gate {
19127c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_kill(&td->tio_cmdbuf, c) == 0)
19137c478bd9Sstevel@tonic-gate 		termio_redraw(td);
19147c478bd9Sstevel@tonic-gate 
19157c478bd9Sstevel@tonic-gate 	return (NULL);
19167c478bd9Sstevel@tonic-gate }
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate static const char *
termio_killfwdword(termio_data_t * td,int c)19197c478bd9Sstevel@tonic-gate termio_killfwdword(termio_data_t *td, int c)
19207c478bd9Sstevel@tonic-gate {
19217c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_killfwdword(&td->tio_cmdbuf, c) == 0)
19227c478bd9Sstevel@tonic-gate 		termio_redraw(td);
19237c478bd9Sstevel@tonic-gate 
19247c478bd9Sstevel@tonic-gate 	return (NULL);
19257c478bd9Sstevel@tonic-gate }
19267c478bd9Sstevel@tonic-gate 
19277c478bd9Sstevel@tonic-gate static const char *
termio_killbackword(termio_data_t * td,int c)19287c478bd9Sstevel@tonic-gate termio_killbackword(termio_data_t *td, int c)
19297c478bd9Sstevel@tonic-gate {
19307c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_killbackword(&td->tio_cmdbuf, c) == 0)
19317c478bd9Sstevel@tonic-gate 		termio_redraw(td);
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	return (NULL);
19347c478bd9Sstevel@tonic-gate }
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate static const char *
termio_reset(termio_data_t * td,int c)19377c478bd9Sstevel@tonic-gate termio_reset(termio_data_t *td, int c)
19387c478bd9Sstevel@tonic-gate {
19397c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_reset(&td->tio_cmdbuf, c) == 0)
19407c478bd9Sstevel@tonic-gate 		termio_clear(td);
19417c478bd9Sstevel@tonic-gate 
19427c478bd9Sstevel@tonic-gate 	return (NULL);
19437c478bd9Sstevel@tonic-gate }
19447c478bd9Sstevel@tonic-gate 
19457c478bd9Sstevel@tonic-gate /*ARGSUSED*/
19467c478bd9Sstevel@tonic-gate static const char *
termio_widescreen(termio_data_t * td,int c)19477c478bd9Sstevel@tonic-gate termio_widescreen(termio_data_t *td, int c)
19487c478bd9Sstevel@tonic-gate {
19497c478bd9Sstevel@tonic-gate 	if (td->tio_flags & TIO_XTERM) {
19507c478bd9Sstevel@tonic-gate 		if (td->tio_cols == 80)
19517c478bd9Sstevel@tonic-gate 			termio_tput(td, TI_DECSET(TI_DECCOLM), 1);
19527c478bd9Sstevel@tonic-gate 		else
19537c478bd9Sstevel@tonic-gate 			termio_tput(td, TI_DECRST(TI_DECCOLM), 1);
19547c478bd9Sstevel@tonic-gate 		mdb_iob_flush(td->tio_out);
19557c478bd9Sstevel@tonic-gate 		termio_winch(SIGWINCH, NULL, NULL, td);
19567c478bd9Sstevel@tonic-gate 	}
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	return (NULL);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate static const char *
termio_prevhist(termio_data_t * td,int c)19627c478bd9Sstevel@tonic-gate termio_prevhist(termio_data_t *td, int c)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_prevhist(&td->tio_cmdbuf, c) == 0)
19657c478bd9Sstevel@tonic-gate 		termio_redraw(td);
19667c478bd9Sstevel@tonic-gate 
19677c478bd9Sstevel@tonic-gate 	return (NULL);
19687c478bd9Sstevel@tonic-gate }
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate static const char *
termio_nexthist(termio_data_t * td,int c)19717c478bd9Sstevel@tonic-gate termio_nexthist(termio_data_t *td, int c)
19727c478bd9Sstevel@tonic-gate {
19737c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_nexthist(&td->tio_cmdbuf, c) == 0)
19747c478bd9Sstevel@tonic-gate 		termio_redraw(td);
19757c478bd9Sstevel@tonic-gate 
19767c478bd9Sstevel@tonic-gate 	return (NULL);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate  * Single-key accelerator support.  Several commands are so commonly used as to
19817c478bd9Sstevel@tonic-gate  * require a single-key equivalent.  If we see one of these accelerator
19827c478bd9Sstevel@tonic-gate  * characters at the beginning of an otherwise-empty line, we'll replace it with
19837c478bd9Sstevel@tonic-gate  * the expansion.
19847c478bd9Sstevel@tonic-gate  */
19857c478bd9Sstevel@tonic-gate static const char *
termio_accel(termio_data_t * td,int c)19867c478bd9Sstevel@tonic-gate termio_accel(termio_data_t *td, int c)
19877c478bd9Sstevel@tonic-gate {
19887c478bd9Sstevel@tonic-gate 	const char *p;
19897c478bd9Sstevel@tonic-gate 
19907c478bd9Sstevel@tonic-gate 	if (td->tio_cmdbuf.cmd_buflen != 0 ||
19917c478bd9Sstevel@tonic-gate 	    (p = termio_accel_lookup(c)) == NULL)
19927c478bd9Sstevel@tonic-gate 		return (termio_insert(td, c));
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	while (*p != '\0')
19957c478bd9Sstevel@tonic-gate 		(void) termio_insert(td, *p++);
19967c478bd9Sstevel@tonic-gate 	return (termio_accept(td, '\n'));
19977c478bd9Sstevel@tonic-gate }
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate static const char *
termio_findhist(termio_data_t * td,int c)20007c478bd9Sstevel@tonic-gate termio_findhist(termio_data_t *td, int c)
20017c478bd9Sstevel@tonic-gate {
20027c478bd9Sstevel@tonic-gate 	if (mdb_cmdbuf_reset(&td->tio_cmdbuf, c) == 0) {
20037c478bd9Sstevel@tonic-gate 		td->tio_prompt = "Search: ";
20047c478bd9Sstevel@tonic-gate 		td->tio_promptlen = strlen(td->tio_prompt);
20057c478bd9Sstevel@tonic-gate 		td->tio_flags |= TIO_FINDHIST;
20067c478bd9Sstevel@tonic-gate 		termio_redraw(td);
20077c478bd9Sstevel@tonic-gate 	}
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	return (NULL);
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20137c478bd9Sstevel@tonic-gate static const char *
termio_refresh(termio_data_t * td,int c)20147c478bd9Sstevel@tonic-gate termio_refresh(termio_data_t *td, int c)
20157c478bd9Sstevel@tonic-gate {
20167c478bd9Sstevel@tonic-gate 	if (td->tio_info.ti_clear.at_str) {
20177c478bd9Sstevel@tonic-gate 		termio_tput(td, td->tio_info.ti_clear.at_str, 1);
20187c478bd9Sstevel@tonic-gate 		td->tio_x = td->tio_y = 0;
20197c478bd9Sstevel@tonic-gate 	}
20207c478bd9Sstevel@tonic-gate 	termio_redraw(td);
20217c478bd9Sstevel@tonic-gate 	return (NULL);
20227c478bd9Sstevel@tonic-gate }
20237c478bd9Sstevel@tonic-gate 
20247c478bd9Sstevel@tonic-gate /*
20257c478bd9Sstevel@tonic-gate  * Leave the terminal read code by longjmp'ing up the stack of mdb_frame_t's
20267c478bd9Sstevel@tonic-gate  * back to the main parsing loop (see mdb_run() in mdb.c).
20277c478bd9Sstevel@tonic-gate  */
20287c478bd9Sstevel@tonic-gate static const char *
termio_abort(termio_data_t * td,int c,int err)20297c478bd9Sstevel@tonic-gate termio_abort(termio_data_t *td, int c, int err)
20307c478bd9Sstevel@tonic-gate {
20317c478bd9Sstevel@tonic-gate 	(void) mdb_cmdbuf_reset(&td->tio_cmdbuf, c);
20327c478bd9Sstevel@tonic-gate 	td->tio_active = FALSE;
20337c478bd9Sstevel@tonic-gate 	td->tio_rti_on = FALSE;
20347c478bd9Sstevel@tonic-gate 
20357c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TCSETSW, &td->tio_dtios) == -1)
20367c478bd9Sstevel@tonic-gate 		warn("failed to restore terminal attributes");
20377c478bd9Sstevel@tonic-gate 
20387c478bd9Sstevel@tonic-gate 	longjmp(mdb.m_frame->f_pcb, err);
20397c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
20407c478bd9Sstevel@tonic-gate 	return (NULL);
20417c478bd9Sstevel@tonic-gate }
20427c478bd9Sstevel@tonic-gate 
20437c478bd9Sstevel@tonic-gate static const char *
termio_intr(termio_data_t * td,int c)20447c478bd9Sstevel@tonic-gate termio_intr(termio_data_t *td, int c)
20457c478bd9Sstevel@tonic-gate {
20467c478bd9Sstevel@tonic-gate 	return (termio_abort(td, c, MDB_ERR_SIGINT));
20477c478bd9Sstevel@tonic-gate }
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate static const char *
termio_quit(termio_data_t * td,int c)20507c478bd9Sstevel@tonic-gate termio_quit(termio_data_t *td, int c)
20517c478bd9Sstevel@tonic-gate {
20527c478bd9Sstevel@tonic-gate 	return (termio_abort(td, c, MDB_ERR_QUIT));
20537c478bd9Sstevel@tonic-gate }
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20567c478bd9Sstevel@tonic-gate static const char *
termio_susp(termio_data_t * td,int c)20577c478bd9Sstevel@tonic-gate termio_susp(termio_data_t *td, int c)
20587c478bd9Sstevel@tonic-gate {
2059*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGWINCH, MDB_SIG_IGN, NULL);
2060*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_IGN, NULL);
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate 	termio_suspend_tty(td, &td->tio_ptios);
20637c478bd9Sstevel@tonic-gate 	mdb_iob_nl(td->tio_out);
20647c478bd9Sstevel@tonic-gate 
2065*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_DFL, NULL);
20667c478bd9Sstevel@tonic-gate 	(void) mdb_signal_pgrp(SIGTSTP);
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	/*
20697c478bd9Sstevel@tonic-gate 	 * When we call mdb_signal_pgrp(SIGTSTP), we are expecting the entire
20707c478bd9Sstevel@tonic-gate 	 * debugger process group to be stopped by the kernel.  Once we return
20717c478bd9Sstevel@tonic-gate 	 * from that call, we assume we are resuming from a subsequent SIGCONT.
20727c478bd9Sstevel@tonic-gate 	 */
2073*30699046SRichard Lowe 	(void) mdb_signal_sethandler(SIGTSTP, MDB_SIG_IGN, NULL);
20747c478bd9Sstevel@tonic-gate 	termio_resume_tty(td, &td->tio_ptios);
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGWINCH, termio_winch, td);
20777c478bd9Sstevel@tonic-gate 	(void) mdb_signal_sethandler(SIGTSTP, termio_tstp, td);
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	if (td->tio_active)
20807c478bd9Sstevel@tonic-gate 		siglongjmp(td->tio_env, SIGCONT);
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	return (NULL);
20837c478bd9Sstevel@tonic-gate }
20847c478bd9Sstevel@tonic-gate 
20857c478bd9Sstevel@tonic-gate /*ARGSUSED*/
20867c478bd9Sstevel@tonic-gate static void
termio_winch(int sig,siginfo_t * sip,ucontext_t * ucp,void * data)20877c478bd9Sstevel@tonic-gate termio_winch(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
20887c478bd9Sstevel@tonic-gate {
20897c478bd9Sstevel@tonic-gate 	termio_data_t *td = data;
20907c478bd9Sstevel@tonic-gate 	mdb_bool_t change = FALSE;
20917c478bd9Sstevel@tonic-gate 	struct winsize winsz;
20927c478bd9Sstevel@tonic-gate 
20937c478bd9Sstevel@tonic-gate 	if (termio_ctl(td->tio_io, TIOCGWINSZ, &winsz) == -1)
20947c478bd9Sstevel@tonic-gate 		return; /* just ignore this WINCH if the ioctl fails */
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	if (td->tio_rows != (size_t)winsz.ws_row ||
20977c478bd9Sstevel@tonic-gate 	    td->tio_cols != (size_t)winsz.ws_col) {
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 		if (td->tio_active)
21007c478bd9Sstevel@tonic-gate 			termio_clear(td);
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 		if (winsz.ws_row != 0)
21037c478bd9Sstevel@tonic-gate 			td->tio_rows = (size_t)winsz.ws_row;
21047c478bd9Sstevel@tonic-gate 
21057c478bd9Sstevel@tonic-gate 		if (winsz.ws_col != 0)
21067c478bd9Sstevel@tonic-gate 			td->tio_cols = (size_t)winsz.ws_col;
21077c478bd9Sstevel@tonic-gate 
21087c478bd9Sstevel@tonic-gate 		if (td->tio_active)
21097c478bd9Sstevel@tonic-gate 			termio_clear(td);
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 		mdb_iob_resize(td->tio_out, td->tio_rows, td->tio_cols);
21127c478bd9Sstevel@tonic-gate 		change = TRUE;
21137c478bd9Sstevel@tonic-gate 	}
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate 	if (change && td->tio_active)
21167c478bd9Sstevel@tonic-gate 		siglongjmp(td->tio_env, sig);
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	if (change && td->tio_link != NULL)
21197c478bd9Sstevel@tonic-gate 		mdb_iob_resize(td->tio_link, td->tio_rows, td->tio_cols);
21207c478bd9Sstevel@tonic-gate }
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate /*ARGSUSED*/
21237c478bd9Sstevel@tonic-gate static void
termio_tstp(int sig,siginfo_t * sip,ucontext_t * ucp,void * data)21247c478bd9Sstevel@tonic-gate termio_tstp(int sig, siginfo_t *sip, ucontext_t *ucp, void *data)
21257c478bd9Sstevel@tonic-gate {
21267c478bd9Sstevel@tonic-gate 	(void) termio_susp(data, CTRL('Z'));
21277c478bd9Sstevel@tonic-gate }
2128