xref: /illumos-gate/usr/src/uts/common/io/ldterm.c (revision 7d8deab2)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2018, Joyent, Inc.
25  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
26  */
27 
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /* All Rights Reserved					*/
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California
34  * All Rights Reserved
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 /*
42  * Standard Streams Terminal Line Discipline module.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/termio.h>
48 #include <sys/stream.h>
49 #include <sys/conf.h>
50 #include <sys/stropts.h>
51 #include <sys/strsubr.h>
52 #include <sys/strsun.h>
53 #include <sys/strtty.h>
54 #include <sys/signal.h>
55 #include <sys/file.h>
56 #include <sys/errno.h>
57 #include <sys/debug.h>
58 #include <sys/cmn_err.h>
59 #include <sys/euc.h>
60 #include <sys/eucioctl.h>
61 #include <sys/csiioctl.h>
62 #include <sys/ptms.h>
63 #include <sys/ldterm.h>
64 #include <sys/cred.h>
65 #include <sys/ddi.h>
66 #include <sys/sunddi.h>
67 #include <sys/kmem.h>
68 #include <sys/modctl.h>
69 
70 /* Time limit when draining during a close(9E) invoked by exit(2) */
71 /* Can be set to zero to emulate the old, broken behavior */
72 int ldterm_drain_limit = 15000000;
73 
74 /*
75  * Character types.
76  */
77 #define	ORDINARY	0
78 #define	CONTROL		1
79 #define	BACKSPACE	2
80 #define	NEWLINE		3
81 #define	TAB		4
82 #define	VTAB		5
83 #define	RETURN		6
84 
85 /*
86  * The following for EUC handling:
87  */
88 #define	T_SS2		7
89 #define	T_SS3		8
90 
91 /*
92  * Table indicating character classes to tty driver.  In particular,
93  * if the class is ORDINARY, then the character needs no special
94  * processing on output.
95  *
96  * Characters in the C1 set are all considered CONTROL; this will
97  * work with terminals that properly use the ANSI/ISO extensions,
98  * but might cause distress with terminals that put graphics in
99  * the range 0200-0237.  On the other hand, characters in that
100  * range cause even greater distress to other UNIX terminal drivers....
101  */
102 
103 static char typetab[256] = {
104 /* 000 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
105 /* 004 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
106 /* 010 */	BACKSPACE,	TAB,		NEWLINE,	CONTROL,
107 /* 014 */	VTAB,		RETURN,		CONTROL,	CONTROL,
108 /* 020 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
109 /* 024 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
110 /* 030 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
111 /* 034 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
112 /* 040 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
113 /* 044 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
114 /* 050 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
115 /* 054 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
116 /* 060 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
117 /* 064 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
118 /* 070 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
119 /* 074 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
120 /* 100 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
121 /* 104 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
122 /* 110 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
123 /* 114 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
124 /* 120 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
125 /* 124 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
126 /* 130 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
127 /* 134 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
128 /* 140 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
129 /* 144 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
130 /* 150 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
131 /* 154 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
132 /* 160 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
133 /* 164 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
134 /* 170 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
135 /* 174 */	ORDINARY,	ORDINARY,	ORDINARY,	CONTROL,
136 /* 200 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
137 /* 204 */	CONTROL,	CONTROL,	T_SS2,		T_SS3,
138 /* 210 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
139 /* 214 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
140 /* 220 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
141 /* 224 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
142 /* 230 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
143 /* 234 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
144 /* 240 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
145 /* 244 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
146 /* 250 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
147 /* 254 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
148 /* 260 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
149 /* 264 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
150 /* 270 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
151 /* 274 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
152 /* 300 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
153 /* 304 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
154 /* 310 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
155 /* 314 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
156 /* 320 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
157 /* 324 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
158 /* 330 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
159 /* 334 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
160 /* 340 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
161 /* 344 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
162 /* 350 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
163 /* 354 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
164 /* 360 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
165 /* 364 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
166 /* 370 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
167 /*
168  * WARNING:  For EUC, 0xFF must be an ordinary character.  It is used with
169  * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
170  * a screen position; in those ISO sets where that position isn't used, it
171  * shouldn't make any difference.
172  */
173 /* 374 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
174 };
175 
176 /*
177  * Translation table for output without OLCUC.  All ORDINARY-class characters
178  * translate to themselves.  All other characters have a zero in the table,
179  * which stops the copying.
180  */
181 static unsigned char notrantab[256] = {
182 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
183 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
184 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
185 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
186 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
187 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
188 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
189 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
190 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
191 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
192 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
193 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
194 /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
195 /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
196 /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
197 /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
198 /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
199 /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
200 /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
201 /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
202 /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
203 /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
204 /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
205 /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
206 /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
207 /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
208 /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
209 /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
210 /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
211 /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
212 /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
213 /*
214  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
215  * itself.
216  */
217 /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
218 };
219 
220 /*
221  * Translation table for output with OLCUC.  All ORDINARY-class characters
222  * translate to themselves, except for lower-case letters which translate
223  * to their upper-case equivalents.  All other characters have a zero in
224  * the table, which stops the copying.
225  */
226 static unsigned char lcuctab[256] = {
227 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
228 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
229 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
230 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
231 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
232 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
233 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
234 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
235 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
236 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
237 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
238 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
239 /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
240 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
241 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
242 /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
243 /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
244 /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
245 /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
246 /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
247 /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
248 /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
249 /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
250 /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
251 /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
252 /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
253 /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
254 /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
255 /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
256 /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
257 /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
258 /*
259  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
260  * itself.
261  */
262 /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
263 };
264 
265 /*
266  * Input mapping table -- if an entry is non-zero, and XCASE is set,
267  * when the corresponding character is typed preceded by "\" the escape
268  * sequence is replaced by the table value.  Mostly used for
269  * upper-case only terminals.
270  */
271 static char	imaptab[256] = {
272 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
273 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
274 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
275 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
276 /* 040 */	0,	'|',	0,	0,	0,	0,	0,	'`',
277 /* 050 */	'{',	'}',	0,	0,	0,	0,	0,	0,
278 /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
279 /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
280 /* 100 */	0,	0,	0,	0,	0,	0,	0,	0,
281 /* 110 */	0,	0,	0,	0,	0,	0,	0,	0,
282 /* 120 */	0,	0,	0,	0,	0,	0,	0,	0,
283 /* 130 */	0,	0,	0,	0,	'\\',	0,	'~',	0,
284 /* 140 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
285 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
286 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
287 /* 170 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
288 /* 200-377 aren't mapped */
289 };
290 
291 /*
292  * Output mapping table -- if an entry is non-zero, and XCASE is set,
293  * the corresponding character is printed as "\" followed by the table
294  * value.  Mostly used for upper-case only terminals.
295  */
296 static char	omaptab[256] = {
297 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
298 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
299 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
300 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
301 /* 040 */	0,	0,	0,	0,	0,	0,	0,	0,
302 /* 050 */	0,	0,	0,	0,	0,	0,	0,	0,
303 /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
304 /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
305 /* 100 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
306 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
307 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
308 /* 130 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
309 /* 140 */	'\'',	0,	0,	0,	0,	0,	0,	0,
310 /* 150 */	0,	0,	0,	0,	0,	0,	0,	0,
311 /* 160 */	0,	0,	0,	0,	0,	0,	0,	0,
312 /* 170 */	0,	0,	0,	'(',	'!',	')',	'^',	0,
313 /* 200-377 aren't mapped */
314 };
315 
316 /*
317  * Translation table for TS_MEUC output without OLCUC.  All printing ASCII
318  * characters translate to themselves.  All other _bytes_ have a zero in
319  * the table, which stops the copying.  This and the following table exist
320  * only so we can use the existing movtuc processing with or without OLCUC.
321  * Maybe it speeds up something...because we can copy a block of characters
322  * by only looking for zeros in the table.
323  *
324  * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
325  * processing, we could rid ourselves of both these tables and save 512 bytes;
326  * seriously, it doesn't make much sense to use olcuc with multi-byte, and
327  * it will probably never be used.  Consideration should be given to disallowing
328  * the combination TS_MEUC & OLCUC.
329  */
330 static unsigned char enotrantab[256] = {
331 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
332 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
333 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
334 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
335 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
336 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
337 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
338 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
339 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
340 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
341 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
342 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
343 /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
344 /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
345 /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
346 /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
347 /* 200 - 377 aren't mapped (they're stoppers). */
348 };
349 
350 /*
351  * Translation table for TS_MEUC output with OLCUC.  All printing ASCII
352  * translate to themselves, except for lower-case letters which translate
353  * to their upper-case equivalents.  All other bytes have a zero in
354  * the table, which stops the copying.  Useless for ISO Latin Alphabet
355  * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
356  * We only have this table so we can use the existing OLCUC processing with
357  * TS_MEUC set (multi-byte mode).  Nobody would ever think of actually
358  * _using_ it...would they?
359  */
360 static unsigned char elcuctab[256] = {
361 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
362 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
363 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
364 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
365 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
366 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
367 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
368 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
369 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
370 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
371 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
372 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
373 /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
374 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
375 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
376 /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
377 /* 200 - 377 aren't mapped (they're stoppers). */
378 };
379 
380 static struct streamtab ldtrinfo;
381 
382 static struct fmodsw fsw = {
383 	"ldterm",
384 	&ldtrinfo,
385 	D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
386 };
387 
388 static struct modlstrmod modlstrmod = {
389 	&mod_strmodops, "terminal line discipline", &fsw
390 };
391 
392 
393 static struct modlinkage modlinkage = {
394 	MODREV_1, &modlstrmod, NULL
395 };
396 
397 
398 int
_init(void)399 _init(void)
400 {
401 	return (mod_install(&modlinkage));
402 }
403 
404 int
_fini(void)405 _fini(void)
406 {
407 	return (mod_remove(&modlinkage));
408 }
409 
410 int
_info(struct modinfo * modinfop)411 _info(struct modinfo *modinfop)
412 {
413 	return (mod_info(&modlinkage, modinfop));
414 }
415 
416 
417 static int	ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
418 static int	ldtermclose(queue_t *, int, cred_t *);
419 static int	ldtermrput(queue_t *, mblk_t *);
420 static int	ldtermrsrv(queue_t *);
421 static int	ldtermrmsg(queue_t *, mblk_t *);
422 static int	ldtermwput(queue_t *, mblk_t *);
423 static int	ldtermwsrv(queue_t *);
424 static int	ldtermwmsg(queue_t *, mblk_t *);
425 static mblk_t	*ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
426 				ldtermstd_state_t *, int *);
427 static int	ldterm_unget(ldtermstd_state_t *);
428 static void	ldterm_trim(ldtermstd_state_t *);
429 static void	ldterm_rubout(unsigned char, queue_t *, size_t,
430 				ldtermstd_state_t *);
431 static int	ldterm_tabcols(ldtermstd_state_t *);
432 static void	ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
433 static void	ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
434 static void	ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
435 static void	ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
436 static mblk_t	*ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
437 					ldtermstd_state_t *);
438 static int	ldterm_echo(unsigned char, queue_t *, size_t,
439 				ldtermstd_state_t *);
440 static void	ldterm_outchar(unsigned char, queue_t *, size_t,
441 				ldtermstd_state_t *);
442 static void	ldterm_outstring(unsigned char *, int, queue_t *, size_t,
443 					ldtermstd_state_t *tp);
444 static mblk_t	*newmsg(ldtermstd_state_t *);
445 static void	ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
446 static void	ldterm_wenable(void *);
447 static mblk_t	*ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
448 				ldtermstd_state_t *, size_t, int);
449 static void	ldterm_flush_output(unsigned char, queue_t *,
450 					ldtermstd_state_t *);
451 static void	ldterm_dosig(queue_t *, int, unsigned char, int, int);
452 static void	ldterm_do_ioctl(queue_t *, mblk_t *);
453 static int	chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
454 static void	ldterm_ioctl_reply(queue_t *, mblk_t *);
455 static void	vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
456 static void	vmin_settimer(queue_t *);
457 static void	vmin_timed_out(void *);
458 static void	ldterm_adjust_modes(ldtermstd_state_t *);
459 static void	ldterm_eucwarn(ldtermstd_state_t *);
460 static void	cp_eucwioc(eucioc_t *, eucioc_t *, int);
461 static int	ldterm_codeset(uchar_t, uchar_t);
462 
463 static void	ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
464 static void	ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
465 
466 static uchar_t	ldterm_utf8_width(uchar_t *, int);
467 
468 /* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
469 static int	__ldterm_dispwidth_euc(uchar_t, void *, int);
470 static int	__ldterm_memwidth_euc(uchar_t, void *);
471 
472 static int	__ldterm_dispwidth_pccs(uchar_t, void *, int);
473 static int	__ldterm_memwidth_pccs(uchar_t, void *);
474 
475 static int	__ldterm_dispwidth_utf8(uchar_t, void *, int);
476 static int	__ldterm_memwidth_utf8(uchar_t, void *);
477 
478 static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
479 	{
480 		NULL,
481 		NULL
482 	},
483 	{
484 		__ldterm_dispwidth_euc,
485 		__ldterm_memwidth_euc
486 	},
487 	{
488 		__ldterm_dispwidth_pccs,
489 		__ldterm_memwidth_pccs
490 	},
491 	{
492 		__ldterm_dispwidth_utf8,
493 		__ldterm_memwidth_utf8
494 	}
495 };
496 
497 /*
498  * The default codeset is presumably C locale's ISO 646 in EUC but
499  * the data structure at below defined as the default codeset data also
500  * support any single byte (EUC) locales.
501  */
502 static const ldterm_cs_data_t default_cs_data = {
503 	LDTERM_DATA_VERSION,
504 	LDTERM_CS_TYPE_EUC,
505 	(uchar_t)0,
506 	(uchar_t)0,
507 	(char *)NULL,
508 	{
509 		'\0', '\0', '\0', '\0',
510 		'\0', '\0', '\0', '\0',
511 		'\0', '\0', '\0', '\0',
512 		'\0', '\0', '\0', '\0',
513 		'\0', '\0', '\0', '\0',
514 		'\0', '\0', '\0', '\0',
515 		'\0', '\0', '\0', '\0',
516 		'\0', '\0', '\0', '\0',
517 		'\0', '\0', '\0', '\0',
518 		'\0', '\0', '\0', '\0'
519 	}
520 };
521 
522 /*
523  * The following tables are from either u8_textprep.c or uconv.c at
524  * usr/src/common/unicode/. The tables are used to figure out corresponding
525  * UTF-8 character byte lengths and also the validity of given character bytes.
526  */
527 extern const int8_t u8_number_of_bytes[];
528 extern const uchar_t u8_masks_tbl[];
529 extern const uint8_t u8_valid_min_2nd_byte[];
530 extern const uint8_t u8_valid_max_2nd_byte[];
531 
532 /*
533  * Unicode character width definition tables from uwidth.c:
534  */
535 extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
536 
537 #ifdef LDDEBUG
538 int	ldterm_debug = 0;
539 #define	DEBUG1(a)	if (ldterm_debug == 1) printf a
540 #define	DEBUG2(a)	if (ldterm_debug >= 2) printf a	/* allocations */
541 #define	DEBUG3(a)	if (ldterm_debug >= 3) printf a	/* M_CTL Stuff */
542 #define	DEBUG4(a)	if (ldterm_debug >= 4) printf a	/* M_READ Stuff */
543 #define	DEBUG5(a)	if (ldterm_debug >= 5) printf a
544 #define	DEBUG6(a)	if (ldterm_debug >= 6) printf a
545 #define	DEBUG7(a)	if (ldterm_debug >= 7) printf a
546 #else
547 #define	DEBUG1(a)
548 #define	DEBUG2(a)
549 #define	DEBUG3(a)
550 #define	DEBUG4(a)
551 #define	DEBUG5(a)
552 #define	DEBUG6(a)
553 #define	DEBUG7(a)
554 #endif		/* LDDEBUG */
555 
556 
557 /*
558  * Since most of the buffering occurs either at the stream head or in
559  * the "message currently being assembled" buffer, we have a
560  * relatively small input queue, so that blockages above us get
561  * reflected fairly quickly to the module below us.  We also have a
562  * small maximum packet size, since you can put a message of that
563  * size on an empty queue no matter how much bigger than the high
564  * water mark it is.
565  */
566 static struct module_info ldtermmiinfo = {
567 	0x0bad,
568 	"ldterm",
569 	0,
570 	_TTY_BUFSIZ,
571 	_TTY_BUFSIZ,
572 	LOWAT
573 };
574 
575 
576 static struct qinit ldtermrinit = {
577 	ldtermrput,
578 	ldtermrsrv,
579 	ldtermopen,
580 	ldtermclose,
581 	NULL,
582 	&ldtermmiinfo
583 };
584 
585 
586 static struct module_info ldtermmoinfo = {
587 	0x0bad,
588 	"ldterm",
589 	0,
590 	INFPSZ,
591 	1,
592 	0
593 };
594 
595 
596 static struct qinit ldtermwinit = {
597 	ldtermwput,
598 	ldtermwsrv,
599 	ldtermopen,
600 	ldtermclose,
601 	NULL,
602 	&ldtermmoinfo
603 };
604 
605 
606 static struct streamtab ldtrinfo = {
607 	&ldtermrinit,
608 	&ldtermwinit,
609 	NULL,
610 	NULL
611 };
612 
613 /*
614  * Dummy qbufcall callback routine used by open and close.
615  * The framework will wake up qwait_sig when we return from
616  * this routine (as part of leaving the perimeters.)
617  * (The framework enters the perimeters before calling the qbufcall() callback
618  * and leaves the perimeters after the callback routine has executed. The
619  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
620  * when it leaves the perimeter. See qwait(9E).)
621  */
622 /* ARGSUSED */
623 static void
dummy_callback(void * arg)624 dummy_callback(void *arg)
625 {}
626 
627 
628 static mblk_t *
open_ioctl(queue_t * q,uint_t cmd)629 open_ioctl(queue_t *q, uint_t cmd)
630 {
631 	mblk_t *mp;
632 	bufcall_id_t id;
633 	int retv;
634 
635 	while ((mp = mkiocb(cmd)) == NULL) {
636 		id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
637 		    dummy_callback, NULL);
638 		retv = qwait_sig(q);
639 		qunbufcall(q, id);
640 		if (retv == 0)
641 			break;
642 	}
643 	return (mp);
644 }
645 
646 static mblk_t *
open_mblk(queue_t * q,size_t len)647 open_mblk(queue_t *q, size_t len)
648 {
649 	mblk_t *mp;
650 	bufcall_id_t id;
651 	int retv;
652 
653 	while ((mp = allocb(len, BPRI_MED)) == NULL) {
654 		id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
655 		retv = qwait_sig(q);
656 		qunbufcall(q, id);
657 		if (retv == 0)
658 			break;
659 	}
660 	return (mp);
661 }
662 
663 /*
664  * Line discipline open.
665  */
666 /* ARGSUSED1 */
667 static int
ldtermopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)668 ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
669 {
670 	ldtermstd_state_t *tp;
671 	mblk_t *bp, *qryp;
672 	int len;
673 	struct stroptions *strop;
674 	struct termios *termiosp;
675 	queue_t *wq;
676 
677 	if (q->q_ptr != NULL) {
678 		return (0);	/* already attached */
679 	}
680 
681 	tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
682 	    KM_SLEEP);
683 
684 	/*
685 	 * Get termios defaults.  These are stored as
686 	 * a property in the "options" node.
687 	 */
688 	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_NOTPROM,
689 	    "ttymodes", (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
690 	    len == sizeof (struct termios)) {
691 		tp->t_modes = *termiosp;
692 		tp->t_amodes = *termiosp;
693 		kmem_free(termiosp, len);
694 	} else {
695 		/*
696 		 * Gack!  Whine about it.
697 		 */
698 		cmn_err(CE_WARN, "ldterm: Couldn't get ttymodes property!");
699 	}
700 	bzero(&tp->t_dmodes, sizeof (struct termios));
701 
702 	tp->t_state = 0;
703 
704 	tp->t_line = 0;
705 	tp->t_col = 0;
706 
707 	tp->t_rocount = 0;
708 	tp->t_rocol = 0;
709 
710 	tp->t_message = NULL;
711 	tp->t_endmsg = NULL;
712 	tp->t_msglen = 0;
713 	tp->t_rd_request = 0;
714 
715 	tp->t_echomp = NULL;
716 	tp->t_iocid = 0;
717 	tp->t_wbufcid = 0;
718 	tp->t_vtid = 0;
719 
720 	q->q_ptr = (caddr_t)tp;
721 	WR(q)->q_ptr = (caddr_t)tp;
722 	/*
723 	 * The following for EUC and also non-EUC codesets:
724 	 */
725 	tp->t_codeset = tp->t_eucleft = tp->t_eucign = tp->t_scratch_len = 0;
726 	bzero(&tp->eucwioc, EUCSIZE);
727 	tp->eucwioc.eucw[0] = 1;	/* ASCII mem & screen width */
728 	tp->eucwioc.scrw[0] = 1;
729 	tp->t_maxeuc = 1;	/* the max len in bytes of an EUC char */
730 	tp->t_eucp = NULL;
731 	tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
732 	tp->t_csdata = default_cs_data;
733 
734 	/*
735 	 * Try to switch to UTF-8 mode by allocating buffer for multibyte
736 	 * chars, keep EUC if allocation fails.
737 	 */
738 	if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ, BPRI_HI)) != NULL) {
739 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
740 		tp->t_state = TS_MEUC;	/* Multibyte mode. */
741 		tp->t_maxeuc = 4; /* the max len in bytes of an UTF-8 char */
742 		tp->t_csdata.codeset_type = LDTERM_CS_TYPE_UTF8;
743 		tp->t_csdata.csinfo_num = 4;
744 		/* locale_name needs string length with terminating NUL */
745 		tp->t_csdata.locale_name = (char *)kmem_alloc(6, KM_SLEEP);
746 		(void) strcpy(tp->t_csdata.locale_name, "UTF-8");
747 		tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_UTF8];
748 	}
749 	tp->t_eucwarn = 0;	/* no bad chars seen yet */
750 
751 	qprocson(q);
752 
753 	/*
754 	 * Find out if the module below us does canonicalization; if
755 	 * so, we won't do it ourselves.
756 	 */
757 
758 	if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
759 		goto open_abort;
760 
761 	/*
762 	 * Reformulate as an M_CTL message. The actual data will
763 	 * be in the b_cont field.
764 	 */
765 	qryp->b_datap->db_type = M_CTL;
766 	wq = OTHERQ(q);
767 	putnext(wq, qryp);
768 
769 	/* allocate a TCSBRK ioctl in case we'll need it on close */
770 	if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
771 		goto open_abort;
772 	tp->t_drainmsg = qryp;
773 	if ((bp = open_mblk(q, sizeof (int))) == NULL)
774 		goto open_abort;
775 	qryp->b_cont = bp;
776 
777 	/*
778 	 * Find out if the underlying driver supports proper POSIX close
779 	 * semantics.  If not, we'll have to approximate it using TCSBRK.  If
780 	 * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
781 	 * the ldtermrput routine.
782 	 *
783 	 * When the ldterm_drain_limit tunable is set to zero, we behave the
784 	 * same as old ldterm: don't send this new message, and always use
785 	 * TCSBRK during close.
786 	 */
787 	if (ldterm_drain_limit != 0) {
788 		if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
789 			goto open_abort;
790 		qryp->b_datap->db_type = M_CTL;
791 		putnext(wq, qryp);
792 	}
793 
794 	/* prepare to clear the water marks on close */
795 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
796 		goto open_abort;
797 	tp->t_closeopts = bp;
798 
799 	/*
800 	 * Set the high-water and low-water marks on the stream head
801 	 * to values appropriate for a terminal.  Also set the "vmin"
802 	 * and "vtime" values to 1 and 0, turn on message-nondiscard
803 	 * mode (as we're in ICANON mode), and turn on "old-style
804 	 * NODELAY" mode.
805 	 */
806 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
807 		goto open_abort;
808 	strop = (struct stroptions *)bp->b_wptr;
809 	strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
810 	strop->so_readopt = RMSGN;
811 	strop->so_hiwat = _TTY_BUFSIZ;
812 	strop->so_lowat = LOWAT;
813 	bp->b_wptr += sizeof (struct stroptions);
814 	bp->b_datap->db_type = M_SETOPTS;
815 	putnext(q, bp);
816 
817 	return (0);		/* this can become a controlling TTY */
818 
819 open_abort:
820 	qprocsoff(q);
821 	q->q_ptr = NULL;
822 	WR(q)->q_ptr = NULL;
823 	freemsg(tp->t_closeopts);
824 	freemsg(tp->t_drainmsg);
825 	/* Dump the state structure */
826 	kmem_free(tp, sizeof (ldtermstd_state_t));
827 	return (EINTR);
828 }
829 
830 struct close_timer {
831 	timeout_id_t id;
832 	ldtermstd_state_t *tp;
833 };
834 
835 static void
drain_timed_out(void * arg)836 drain_timed_out(void *arg)
837 {
838 	struct close_timer *ctp = arg;
839 
840 	ctp->id = 0;
841 	ctp->tp->t_state &= ~TS_IOCWAIT;
842 }
843 
844 /* ARGSUSED2 */
845 static int
ldtermclose(queue_t * q,int cflag,cred_t * crp)846 ldtermclose(queue_t *q, int cflag, cred_t *crp)
847 {
848 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
849 	struct stroptions *strop;
850 	mblk_t *bp;
851 	struct close_timer cltimer;
852 
853 	/*
854 	 * If we have an outstanding vmin timeout, cancel it.
855 	 */
856 	tp->t_state |= TS_CLOSE;
857 	if (tp->t_vtid != 0)
858 		(void) quntimeout(q, tp->t_vtid);
859 	tp->t_vtid = 0;
860 
861 	/*
862 	 * Cancel outstanding qbufcall request.
863 	 */
864 	if (tp->t_wbufcid != 0)
865 		qunbufcall(q, tp->t_wbufcid);
866 
867 	/*
868 	 * Reset the high-water and low-water marks on the stream
869 	 * head (?), turn on byte-stream mode, and turn off
870 	 * "old-style NODELAY" mode.
871 	 */
872 	bp = tp->t_closeopts;
873 	strop = (struct stroptions *)bp->b_wptr;
874 	strop->so_flags = SO_READOPT|SO_NDELOFF;
875 	strop->so_readopt = RNORM;
876 	bp->b_wptr += sizeof (struct stroptions);
877 	bp->b_datap->db_type = M_SETOPTS;
878 	putnext(q, bp);
879 
880 	if (cflag & (FNDELAY|FNONBLOCK)) {
881 		freemsg(tp->t_drainmsg);
882 	} else if ((bp = tp->t_drainmsg) != NULL) {
883 		struct iocblk *iocb;
884 
885 		/*
886 		 * If the driver isn't known to have POSIX close semantics,
887 		 * then we have to emulate this the old way.  This is done by
888 		 * sending down TCSBRK,1 to drain the output and waiting for
889 		 * the reply.
890 		 */
891 		iocb = (struct iocblk *)bp->b_rptr;
892 		iocb->ioc_count = sizeof (int);
893 		*(int *)bp->b_cont->b_rptr = 1;
894 		bp->b_cont->b_wptr += sizeof (int);
895 		tp->t_state |= TS_IOCWAIT;
896 		tp->t_iocid = iocb->ioc_id;
897 		if (!putq(WR(q), bp))
898 			putnext(WR(q), bp);
899 
900 		/*
901 		 * If we're not able to receive signals at this point, then
902 		 * launch a timer.  This timer will prevent us from waiting
903 		 * forever for a signal that won't arrive.
904 		 */
905 		cltimer.id = 0;
906 		if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
907 			cltimer.tp = tp;
908 			cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
909 			    drv_usectohz(ldterm_drain_limit));
910 		}
911 
912 		/*
913 		 * Note that the read side of ldterm and the qtimeout are
914 		 * protected by D_MTQPAIR, so no additional locking is needed
915 		 * here.
916 		 */
917 		while (tp->t_state & TS_IOCWAIT) {
918 			if (qwait_sig(q) == 0)
919 				break;
920 		}
921 		if (cltimer.id != 0)
922 			(void) quntimeout(q, cltimer.id);
923 	}
924 
925 	/*
926 	 * From here to the end, the routine does not sleep and does not
927 	 * reference STREAMS, so it's guaranteed to run to completion.
928 	 */
929 
930 	qprocsoff(q);
931 
932 	freemsg(tp->t_message);
933 	freemsg(tp->t_eucp_mp);
934 
935 	/* Dump the state structure, then unlink it */
936 	if (tp->t_csdata.locale_name != NULL)
937 		kmem_free(tp->t_csdata.locale_name,
938 		    strlen(tp->t_csdata.locale_name) + 1);
939 	kmem_free(tp, sizeof (ldtermstd_state_t));
940 	q->q_ptr = NULL;
941 	return (0);
942 }
943 
944 
945 /*
946  * Put procedure for input from driver end of stream (read queue).
947  */
948 static int
ldtermrput(queue_t * q,mblk_t * mp)949 ldtermrput(queue_t *q, mblk_t *mp)
950 {
951 	ldtermstd_state_t *tp;
952 	unsigned char c;
953 	queue_t *wrq = WR(q);		/* write queue of ldterm mod */
954 	queue_t *nextq = q->q_next;	/* queue below us */
955 	mblk_t *bp;
956 	struct iocblk *qryp;
957 	unsigned char *readp;
958 	unsigned char *writep;
959 	struct termios *emodes;		/* effective modes set by driver */
960 	int dbtype;
961 
962 	tp = (ldtermstd_state_t *)q->q_ptr;
963 	/*
964 	 * We received our ack from the driver saying there is nothing left to
965 	 * shovel out, so wake up the close routine.
966 	 */
967 	dbtype = DB_TYPE(mp);
968 	if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
969 	    (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
970 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
971 
972 		if (iocp->ioc_id == tp->t_iocid) {
973 			tp->t_state &= ~TS_IOCWAIT;
974 			freemsg(mp);
975 			return (0);
976 		}
977 	}
978 
979 	switch (dbtype) {
980 
981 	default:
982 		(void) putq(q, mp);
983 		return (0);
984 
985 		/*
986 		 * Send these up unmolested
987 		 *
988 		 */
989 	case M_PCSIG:
990 	case M_SIG:
991 	case M_IOCNAK:
992 
993 		putnext(q, mp);
994 		return (0);
995 
996 	case M_IOCACK:
997 
998 		ldterm_ioctl_reply(q, mp);
999 		return (0);
1000 
1001 	case M_BREAK:
1002 
1003 		/*
1004 		 * Parity errors are sent up as M_BREAKS with single
1005 		 * character data (formerly handled in the driver)
1006 		 */
1007 		if (mp->b_wptr - mp->b_rptr == 1) {
1008 			/*
1009 			 * IGNPAR	PARMRK		RESULT
1010 			 * off		off		0
1011 			 * off		on		3 byte sequence
1012 			 * on		either		ignored
1013 			 */
1014 			if (!(tp->t_amodes.c_iflag & IGNPAR)) {
1015 				mp->b_wptr = mp->b_rptr;
1016 				if (tp->t_amodes.c_iflag & PARMRK) {
1017 					unsigned char c;
1018 
1019 					c = *mp->b_rptr;
1020 					freemsg(mp);
1021 					if ((mp = allocb(3, BPRI_HI)) == NULL) {
1022 						cmn_err(CE_WARN,
1023 						    "ldtermrput: no blocks");
1024 						return (0);
1025 					}
1026 					mp->b_datap->db_type = M_DATA;
1027 					*mp->b_wptr++ = (uchar_t)'\377';
1028 					*mp->b_wptr++ = '\0';
1029 					*mp->b_wptr++ = c;
1030 					putnext(q, mp);
1031 				} else {
1032 					mp->b_datap->db_type = M_DATA;
1033 					*mp->b_wptr++ = '\0';
1034 					putnext(q, mp);
1035 				}
1036 			} else {
1037 				freemsg(mp);
1038 			}
1039 			return (0);
1040 		}
1041 		/*
1042 		 * We look at the apparent modes here instead of the
1043 		 * effective modes. Effective modes cannot be used if
1044 		 * IGNBRK, BRINT and PARMRK have been negotiated to
1045 		 * be handled by the driver. Since M_BREAK should be
1046 		 * sent upstream only if break processing was not
1047 		 * already done, it should be ok to use the apparent
1048 		 * modes.
1049 		 */
1050 
1051 		if (!(tp->t_amodes.c_iflag & IGNBRK)) {
1052 			if (tp->t_amodes.c_iflag & BRKINT) {
1053 				ldterm_dosig(q, SIGINT, '\0', M_PCSIG, FLUSHRW);
1054 				freemsg(mp);
1055 			} else if (tp->t_amodes.c_iflag & PARMRK) {
1056 				/*
1057 				 * Send '\377','\0', '\0'.
1058 				 */
1059 				freemsg(mp);
1060 				if ((mp = allocb(3, BPRI_HI)) == NULL) {
1061 					cmn_err(CE_WARN,
1062 					    "ldtermrput: no blocks");
1063 					return (0);
1064 				}
1065 				mp->b_datap->db_type = M_DATA;
1066 				*mp->b_wptr++ = (uchar_t)'\377';
1067 				*mp->b_wptr++ = '\0';
1068 				*mp->b_wptr++ = '\0';
1069 				putnext(q, mp);
1070 			} else {
1071 				/*
1072 				 * Act as if a '\0' came in.
1073 				 */
1074 				freemsg(mp);
1075 				if ((mp = allocb(1, BPRI_HI)) == NULL) {
1076 					cmn_err(CE_WARN,
1077 					    "ldtermrput: no blocks");
1078 					return (0);
1079 				}
1080 				mp->b_datap->db_type = M_DATA;
1081 				*mp->b_wptr++ = '\0';
1082 				putnext(q, mp);
1083 			}
1084 		} else {
1085 			freemsg(mp);
1086 		}
1087 		return (0);
1088 
1089 	case M_CTL:
1090 		DEBUG3(("ldtermrput: M_CTL received\n"));
1091 		/*
1092 		 * The M_CTL has been standardized to look like an
1093 		 * M_IOCTL message.
1094 		 */
1095 
1096 		if ((mp->b_wptr - mp->b_rptr) != sizeof (struct iocblk)) {
1097 			DEBUG3((
1098 			    "Non standard M_CTL received by ldterm module\n"));
1099 			/* May be for someone else; pass it on */
1100 			putnext(q, mp);
1101 			return (0);
1102 		}
1103 		qryp = (struct iocblk *)mp->b_rptr;
1104 
1105 		switch (qryp->ioc_cmd) {
1106 
1107 		case MC_PART_CANON:
1108 
1109 			DEBUG3(("ldtermrput: M_CTL Query Reply\n"));
1110 			if (!mp->b_cont) {
1111 				DEBUG3(("No information in Query Message\n"));
1112 				break;
1113 			}
1114 			if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
1115 			    sizeof (struct termios)) {
1116 				DEBUG3(("ldtermrput: M_CTL GrandScheme\n"));
1117 				/* elaborate turning off scheme */
1118 				emodes = (struct termios *)mp->b_cont->b_rptr;
1119 				bcopy(emodes, &tp->t_dmodes,
1120 					sizeof (struct termios));
1121 				ldterm_adjust_modes(tp);
1122 				break;
1123 			} else {
1124 				DEBUG3(("Incorrect query replysize\n"));
1125 				break;
1126 			}
1127 
1128 		case MC_NO_CANON:
1129 			tp->t_state |= TS_NOCANON;
1130 			/*
1131 			 * Note: this is very nasty.  It's not clear
1132 			 * what the right thing to do with a partial
1133 			 * message is; We throw it out
1134 			 */
1135 			if (tp->t_message != NULL) {
1136 				freemsg(tp->t_message);
1137 				tp->t_message = NULL;
1138 				tp->t_endmsg = NULL;
1139 				tp->t_msglen = 0;
1140 				tp->t_rocount = 0;
1141 				tp->t_rocol = 0;
1142 				if (tp->t_state & TS_MEUC) {
1143 					ASSERT(tp->t_eucp_mp);
1144 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
1145 					tp->t_codeset = 0;
1146 					tp->t_eucleft = 0;
1147 				}
1148 			}
1149 			break;
1150 
1151 		case MC_DO_CANON:
1152 			tp->t_state &= ~TS_NOCANON;
1153 			break;
1154 
1155 		case MC_HAS_POSIX:
1156 			/* no longer any reason to drain from ldterm */
1157 			if (ldterm_drain_limit != 0) {
1158 				freemsg(tp->t_drainmsg);
1159 				tp->t_drainmsg = NULL;
1160 			}
1161 			break;
1162 
1163 		default:
1164 			DEBUG3(("Unknown M_CTL Message\n"));
1165 			break;
1166 		}
1167 		putnext(q, mp);	/* In case anyone else has to see it */
1168 		return (0);
1169 
1170 	case M_FLUSH:
1171 		/*
1172 		 * Flush everything we haven't looked at yet.
1173 		 */
1174 
1175 		if ((tp->t_state & TS_ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
1176 			flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1177 		else
1178 			flushq(q, FLUSHDATA);
1179 
1180 		/*
1181 		 * Flush everything we have looked at.
1182 		 */
1183 		freemsg(tp->t_message);
1184 		tp->t_message = NULL;
1185 		tp->t_endmsg = NULL;
1186 		tp->t_msglen = 0;
1187 		tp->t_rocount = 0;
1188 		tp->t_rocol = 0;
1189 		if (tp->t_state & TS_MEUC) {	/* EUC multi-byte */
1190 			ASSERT(tp->t_eucp_mp);
1191 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1192 		}
1193 		putnext(q, mp);	/* pass it on */
1194 
1195 		/*
1196 		 * Relieve input flow control
1197 		 */
1198 		if ((tp->t_modes.c_iflag & IXOFF) &&
1199 		    (tp->t_state & TS_TBLOCK) &&
1200 		    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1201 			tp->t_state &= ~TS_TBLOCK;
1202 			(void) putnextctl(wrq, M_STARTI);
1203 			DEBUG1(("M_STARTI down\n"));
1204 		}
1205 		return (0);
1206 
1207 	case M_DATA:
1208 		break;
1209 	}
1210 	(void) drv_setparm(SYSRAWC, msgdsize(mp));
1211 
1212 	/*
1213 	 * Flow control: send "start input" message if blocked and
1214 	 * our queue is below its low water mark.
1215 	 */
1216 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
1217 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1218 		tp->t_state &= ~TS_TBLOCK;
1219 		(void) putnextctl(wrq, M_STARTI);
1220 		DEBUG1(("M_STARTI down\n"));
1221 	}
1222 	/*
1223 	 * If somebody below us ("intelligent" communications
1224 	 * board, pseudo-tty controlled by an editor) is doing
1225 	 * canonicalization, don't scan it for special characters.
1226 	 */
1227 	if (tp->t_state & TS_NOCANON) {
1228 		(void) putq(q, mp);
1229 		return (0);
1230 	}
1231 	bp = mp;
1232 
1233 	do {
1234 		readp = bp->b_rptr;
1235 		writep = readp;
1236 		if (tp->t_modes.c_iflag & (INLCR|IGNCR|ICRNL|IUCLC|IXON) ||
1237 		    tp->t_modes.c_lflag & (ISIG|ICANON)) {
1238 			/*
1239 			 * We're doing some sort of non-trivial
1240 			 * processing of input; look at every
1241 			 * character.
1242 			 */
1243 			while (readp < bp->b_wptr) {
1244 				c = *readp++;
1245 
1246 				if (tp->t_modes.c_iflag & ISTRIP)
1247 					c &= 0177;
1248 
1249 				/*
1250 				 * First, check that this hasn't been
1251 				 * escaped with the "literal next"
1252 				 * character.
1253 				 */
1254 				if (tp->t_state & TS_PLNCH) {
1255 					tp->t_state &= ~TS_PLNCH;
1256 					tp->t_modes.c_lflag &= ~FLUSHO;
1257 					*writep++ = c;
1258 					continue;
1259 				}
1260 				/*
1261 				 * Setting a special character to NUL
1262 				 * disables it, so if this character
1263 				 * is NUL, it should not be compared
1264 				 * with any of the special characters.
1265 				 * It should, however, restart frozen
1266 				 * output if IXON and IXANY are set.
1267 				 */
1268 				if (c == _POSIX_VDISABLE) {
1269 					if (tp->t_modes.c_iflag & IXON &&
1270 					    tp->t_state & TS_TTSTOP &&
1271 					    tp->t_modes.c_lflag & IEXTEN &&
1272 					    tp->t_modes.c_iflag & IXANY) {
1273 						tp->t_state &=
1274 						    ~(TS_TTSTOP|TS_OFBLOCK);
1275 						(void) putnextctl(wrq, M_START);
1276 					}
1277 					tp->t_modes.c_lflag &= ~FLUSHO;
1278 					*writep++ = c;
1279 					continue;
1280 				}
1281 				/*
1282 				 * If stopped, start if you can; if
1283 				 * running, stop if you must.
1284 				 */
1285 				if (tp->t_modes.c_iflag & IXON) {
1286 					if (tp->t_state & TS_TTSTOP) {
1287 						if (c ==
1288 						    tp->t_modes.c_cc[VSTART] ||
1289 						    (tp->t_modes.c_lflag &
1290 						    IEXTEN &&
1291 						    tp->t_modes.c_iflag &
1292 						    IXANY)) {
1293 							tp->t_state &=
1294 							    ~(TS_TTSTOP |
1295 							    TS_OFBLOCK);
1296 							(void) putnextctl(wrq,
1297 							    M_START);
1298 						}
1299 					} else {
1300 						if (c ==
1301 						    tp->t_modes.c_cc[VSTOP]) {
1302 							tp->t_state |=
1303 							    TS_TTSTOP;
1304 							(void) putnextctl(wrq,
1305 							    M_STOP);
1306 						}
1307 					}
1308 					if (c == tp->t_modes.c_cc[VSTOP] ||
1309 					    c == tp->t_modes.c_cc[VSTART])
1310 						continue;
1311 				}
1312 				/*
1313 				 * Check for "literal next" character
1314 				 * and "flush output" character.
1315 				 * Note that we omit checks for ISIG
1316 				 * and ICANON, since the IEXTEN
1317 				 * setting subsumes them.
1318 				 */
1319 				if (tp->t_modes.c_lflag & IEXTEN) {
1320 					if (c == tp->t_modes.c_cc[VLNEXT]) {
1321 						/*
1322 						 * Remember that we saw a
1323 						 * "literal next" while
1324 						 * scanning input, but leave
1325 						 * leave it in the message so
1326 						 * that the service routine
1327 						 * can see it too.
1328 						 */
1329 						tp->t_state |= TS_PLNCH;
1330 						tp->t_modes.c_lflag &= ~FLUSHO;
1331 						*writep++ = c;
1332 						continue;
1333 					}
1334 					if (c == tp->t_modes.c_cc[VDISCARD]) {
1335 						ldterm_flush_output(c, wrq, tp);
1336 						continue;
1337 					}
1338 				}
1339 				tp->t_modes.c_lflag &= ~FLUSHO;
1340 
1341 				/*
1342 				 * Check for signal-generating
1343 				 * characters.
1344 				 */
1345 				if (tp->t_modes.c_lflag & ISIG) {
1346 					if (c == tp->t_modes.c_cc[VINTR]) {
1347 						ldterm_dosig(q, SIGINT, c,
1348 						    M_PCSIG, FLUSHRW);
1349 						continue;
1350 					}
1351 					if (c == tp->t_modes.c_cc[VQUIT]) {
1352 						ldterm_dosig(q, SIGQUIT, c,
1353 						    M_PCSIG, FLUSHRW);
1354 						continue;
1355 					}
1356 					if (c == tp->t_modes.c_cc[VSWTCH]) {
1357 						/*
1358 						 * Ancient SXT support; discard
1359 						 * character without action.
1360 						 */
1361 						continue;
1362 					}
1363 					if (c == tp->t_modes.c_cc[VSUSP]) {
1364 						ldterm_dosig(q, SIGTSTP, c,
1365 						    M_PCSIG, FLUSHRW);
1366 						continue;
1367 					}
1368 					if ((tp->t_modes.c_lflag & IEXTEN) &&
1369 					    (c == tp->t_modes.c_cc[VDSUSP])) {
1370 						ldterm_dosig(q, SIGTSTP, c,
1371 						    M_SIG, 0);
1372 						continue;
1373 					}
1374 
1375 					/*
1376 					 * Consumers do not expect the ^T to be
1377 					 * echoed out when we generate a
1378 					 * VSTATUS.
1379 					 */
1380 					if (c == tp->t_modes.c_cc[VSTATUS]) {
1381 						ldterm_dosig(q, SIGINFO, '\0',
1382 						    M_PCSIG, FLUSHRW);
1383 						continue;
1384 					}
1385 				}
1386 				/*
1387 				 * Throw away CR if IGNCR set, or
1388 				 * turn it into NL if ICRNL set.
1389 				 */
1390 				if (c == '\r') {
1391 					if (tp->t_modes.c_iflag & IGNCR)
1392 						continue;
1393 					if (tp->t_modes.c_iflag & ICRNL)
1394 						c = '\n';
1395 				} else {
1396 					/*
1397 					 * Turn NL into CR if INLCR
1398 					 * set.
1399 					 */
1400 					if (c == '\n' &&
1401 					    tp->t_modes.c_iflag & INLCR)
1402 						c = '\r';
1403 				}
1404 
1405 				/*
1406 				 * Map upper case input to lower case
1407 				 * if IUCLC flag set.
1408 				 */
1409 				if (tp->t_modes.c_iflag & IUCLC &&
1410 				    c >= 'A' && c <= 'Z')
1411 					c += 'a' - 'A';
1412 
1413 				/*
1414 				 * Put the possibly-transformed
1415 				 * character back in the message.
1416 				 */
1417 				*writep++ = c;
1418 			}
1419 
1420 			/*
1421 			 * If we didn't copy some characters because
1422 			 * we were ignoring them, fix the size of the
1423 			 * data block by adjusting the write pointer.
1424 			 * XXX This may result in a zero-length
1425 			 * block; will this cause anybody gastric
1426 			 * distress?
1427 			 */
1428 			bp->b_wptr -= (readp - writep);
1429 		} else {
1430 			/*
1431 			 * We won't be doing anything other than
1432 			 * possibly stripping the input.
1433 			 */
1434 			if (tp->t_modes.c_iflag & ISTRIP) {
1435 				while (readp < bp->b_wptr)
1436 					*writep++ = *readp++ & 0177;
1437 			}
1438 			tp->t_modes.c_lflag &= ~FLUSHO;
1439 		}
1440 
1441 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
1442 
1443 	/*
1444 	 * Queue the message for service procedure if the
1445 	 * queue is not empty or canputnext() fails or
1446 	 * tp->t_state & TS_RESCAN is true.
1447 	 */
1448 
1449 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
1450 	    (tp->t_state & TS_RESCAN))
1451 		(void) putq(q, mp);
1452 	else
1453 		(void) ldtermrmsg(q, mp);
1454 
1455 	/*
1456 	 * Flow control: send "stop input" message if our queue is
1457 	 * approaching its high-water mark. The message will be
1458 	 * dropped on the floor in the service procedure, if we
1459 	 * cannot ship it up and we have had it upto our neck!
1460 	 *
1461 	 * Set QWANTW to ensure that the read queue service procedure
1462 	 * gets run when nextq empties up again, so that it can
1463 	 * unstop the input.
1464 	 */
1465 	if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
1466 	    q->q_count >= TTXOHI) {
1467 		mutex_enter(QLOCK(nextq));
1468 		nextq->q_flag |= QWANTW;
1469 		mutex_exit(QLOCK(nextq));
1470 		tp->t_state |= TS_TBLOCK;
1471 		(void) putnextctl(wrq, M_STOPI);
1472 		DEBUG1(("M_STOPI down\n"));
1473 	}
1474 	return (0);
1475 }
1476 
1477 
1478 /*
1479  * Line discipline input server processing.  Erase/kill and escape
1480  * ('\') processing, gathering into messages, upper/lower case input
1481  * mapping.
1482  */
1483 static int
ldtermrsrv(queue_t * q)1484 ldtermrsrv(queue_t *q)
1485 {
1486 	ldtermstd_state_t *tp;
1487 	mblk_t *mp;
1488 
1489 	tp = (ldtermstd_state_t *)q->q_ptr;
1490 
1491 	if (tp->t_state & TS_RESCAN) {
1492 		/*
1493 		 * Canonicalization was turned on or off. Put the
1494 		 * message being assembled back in the input queue,
1495 		 * so that we rescan it.
1496 		 */
1497 		if (tp->t_message != NULL) {
1498 			DEBUG5(("RESCAN WAS SET; put back in q\n"));
1499 			if (tp->t_msglen != 0)
1500 				(void) putbq(q, tp->t_message);
1501 			else
1502 				freemsg(tp->t_message);
1503 			tp->t_message = NULL;
1504 			tp->t_endmsg = NULL;
1505 			tp->t_msglen = 0;
1506 		}
1507 		if (tp->t_state & TS_MEUC) {
1508 			ASSERT(tp->t_eucp_mp);
1509 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1510 			tp->t_codeset = 0;
1511 			tp->t_eucleft = 0;
1512 		}
1513 		tp->t_state &= ~TS_RESCAN;
1514 	}
1515 
1516 	while ((mp = getq(q)) != NULL) {
1517 		if (!ldtermrmsg(q, mp))
1518 			break;
1519 	}
1520 
1521 	/*
1522 	 * Flow control: send start message if blocked and our queue
1523 	 * is below its low water mark.
1524 	 */
1525 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
1526 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1527 		tp->t_state &= ~TS_TBLOCK;
1528 		(void) putctl(WR(q), M_STARTI);
1529 	}
1530 	return (0);
1531 }
1532 
1533 /*
1534  * This routine is called from both ldtermrput and ldtermrsrv to
1535  * do the actual work of dealing with mp. Return 1 on sucesss and
1536  * 0 on failure.
1537  */
1538 static int
ldtermrmsg(queue_t * q,mblk_t * mp)1539 ldtermrmsg(queue_t *q, mblk_t *mp)
1540 {
1541 	unsigned char c;
1542 	int dofree;
1543 	int status = 1;
1544 	size_t   ebsize;
1545 	mblk_t *bp;
1546 	mblk_t *bpt;
1547 	ldtermstd_state_t *tp;
1548 
1549 	bpt = NULL;
1550 
1551 	tp = (ldtermstd_state_t *)q->q_ptr;
1552 
1553 	if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
1554 		/*
1555 		 * Stream head is flow controlled. If echo is
1556 		 * turned on, flush the read side or send a
1557 		 * bell down the line to stop input and
1558 		 * process the current message.
1559 		 * Otherwise(putbq) the user will not see any
1560 		 * response to to the typed input. Typically
1561 		 * happens if there is no reader process.
1562 		 * Note that you will loose the data in this
1563 		 * case if the data is coming too fast. There
1564 		 * is an assumption here that if ECHO is
1565 		 * turned on its some user typing the data on
1566 		 * a terminal and its not network.
1567 		 */
1568 		if (tp->t_modes.c_lflag & ECHO) {
1569 			if ((tp->t_modes.c_iflag & IMAXBEL) &&
1570 			    (tp->t_modes.c_lflag & ICANON)) {
1571 				freemsg(mp);
1572 				if (canputnext(WR(q)))
1573 					ldterm_outchar(CTRL('g'), WR(q), 4, tp);
1574 				status = 0;
1575 				goto echo;
1576 			} else {
1577 				(void) putctl1(q, M_FLUSH, FLUSHR);
1578 			}
1579 		} else {
1580 			(void) putbq(q, mp);
1581 			status = 0;
1582 			goto out;	/* read side is blocked */
1583 		}
1584 	}
1585 	switch (mp->b_datap->db_type) {
1586 
1587 	default:
1588 		putnext(q, mp);	/* pass it on */
1589 		goto out;
1590 
1591 	case M_HANGUP:
1592 		/*
1593 		 * Flush everything we haven't looked at yet.
1594 		 */
1595 		flushq(q, FLUSHDATA);
1596 
1597 		/*
1598 		 * Flush everything we have looked at.
1599 		 */
1600 		freemsg(tp->t_message);
1601 		tp->t_message = NULL;
1602 		tp->t_endmsg = NULL;
1603 		tp->t_msglen = 0;
1604 		/*
1605 		 * XXX  should we set read request
1606 		 * tp->t_rd_request to NULL?
1607 		 */
1608 		tp->t_rocount = 0;	/* if it hasn't been typed */
1609 		tp->t_rocol = 0;	/* it hasn't been echoed :-) */
1610 		if (tp->t_state & TS_MEUC) {
1611 			ASSERT(tp->t_eucp_mp);
1612 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1613 		}
1614 		/*
1615 		 * Restart output, since it's probably got
1616 		 * nowhere to go anyway, and we're probably
1617 		 * not going to see another ^Q for a while.
1618 		 */
1619 		if (tp->t_state & TS_TTSTOP) {
1620 			tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
1621 			(void) putnextctl(WR(q), M_START);
1622 		}
1623 		/*
1624 		 * This message will travel up the read
1625 		 * queue, flushing as it goes, get turned
1626 		 * around at the stream head, and travel back
1627 		 * down the write queue, flushing as it goes.
1628 		 */
1629 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
1630 
1631 		/*
1632 		 * This message will travel down the write
1633 		 * queue, flushing as it goes, get turned
1634 		 * around at the driver, and travel back up
1635 		 * the read queue, flushing as it goes.
1636 		 */
1637 		(void) putctl1(WR(q), M_FLUSH, FLUSHR);
1638 
1639 		/*
1640 		 * Now that that's done, we send a SIGCONT
1641 		 * upstream, followed by the M_HANGUP.
1642 		 */
1643 		/* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
1644 		putnext(q, mp);
1645 		goto out;
1646 
1647 	case M_IOCACK:
1648 
1649 		/*
1650 		 * Augment whatever information the driver is
1651 		 * returning  with the information we supply.
1652 		 */
1653 		ldterm_ioctl_reply(q, mp);
1654 		goto out;
1655 
1656 	case M_DATA:
1657 		break;
1658 	}
1659 
1660 	/*
1661 	 * This is an M_DATA message.
1662 	 */
1663 
1664 	/*
1665 	 * If somebody below us ("intelligent" communications
1666 	 * board, pseudo-tty controlled by an editor) is
1667 	 * doing canonicalization, don't scan it for special
1668 	 * characters.
1669 	 */
1670 	if (tp->t_state & TS_NOCANON) {
1671 		putnext(q, mp);
1672 		goto out;
1673 	}
1674 	bp = mp;
1675 
1676 	if ((bpt = newmsg(tp)) != NULL) {
1677 		mblk_t *bcont;
1678 
1679 		do {
1680 			ASSERT(bp->b_wptr >= bp->b_rptr);
1681 			ebsize = bp->b_wptr - bp->b_rptr;
1682 			if (ebsize > EBSIZE)
1683 				ebsize = EBSIZE;
1684 			bcont = bp->b_cont;
1685 			if (CANON_MODE) {
1686 				/*
1687 				 * By default, free the message once processed
1688 				 */
1689 				dofree = 1;
1690 
1691 				/*
1692 				 * update sysinfo canch
1693 				 * character. The value of
1694 				 * canch may vary as compared
1695 				 * to character tty
1696 				 * implementation.
1697 				 */
1698 				while (bp->b_rptr < bp->b_wptr) {
1699 					c = *bp->b_rptr++;
1700 					if ((bpt = ldterm_docanon(c,
1701 					    bpt, ebsize, q, tp, &dofree)) ==
1702 					    NULL)
1703 						break;
1704 				}
1705 				/*
1706 				 * Release this block or put back on queue.
1707 				 */
1708 				if (dofree)
1709 					freeb(bp);
1710 				else {
1711 					(void) putbq(q, bp);
1712 					break;
1713 				}
1714 			} else
1715 				bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
1716 			if (bpt == NULL) {
1717 				cmn_err(CE_WARN,
1718 				    "ldtermrsrv: out of blocks");
1719 				freemsg(bcont);
1720 				break;
1721 			}
1722 		} while ((bp = bcont) != NULL);
1723 	}
1724 echo:
1725 	/*
1726 	 * Send whatever we echoed downstream.
1727 	 */
1728 	if (tp->t_echomp != NULL) {
1729 		if (canputnext(WR(q)))
1730 			putnext(WR(q), tp->t_echomp);
1731 		else
1732 			freemsg(tp->t_echomp);
1733 		tp->t_echomp = NULL;
1734 	}
1735 
1736 out:
1737 	return (status);
1738 }
1739 
1740 
1741 /*
1742  * Do canonical mode input; check whether this character is to be
1743  * treated as a special character - if so, check whether it's equal
1744  * to any of the special characters and handle it accordingly.
1745  * Otherwise, just add it to the current line.
1746  */
1747 static mblk_t *
ldterm_docanon(uchar_t c,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp,int * dofreep)1748 ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
1749     ldtermstd_state_t *tp, int *dofreep)
1750 {
1751 	queue_t *wrq = WR(q);
1752 	int i;
1753 
1754 	/*
1755 	 * If the previous character was the "literal next"
1756 	 * character, treat this character as regular input.
1757 	 */
1758 	if (tp->t_state & TS_SLNCH)
1759 		goto escaped;
1760 
1761 	/*
1762 	 * Setting a special character to NUL disables it, so if this
1763 	 * character is NUL, it should not be compared with any of
1764 	 * the special characters.
1765 	 */
1766 	if (c == _POSIX_VDISABLE) {
1767 		tp->t_state &= ~TS_QUOT;
1768 		goto escaped;
1769 	}
1770 	/*
1771 	 * If this character is the literal next character, echo it
1772 	 * as '^', backspace over it, and record that fact.
1773 	 */
1774 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
1775 		if (tp->t_modes.c_lflag & ECHO)
1776 			ldterm_outstring((unsigned char *)"^\b", 2, wrq,
1777 			    ebsize, tp);
1778 		tp->t_state |= TS_SLNCH;
1779 		goto out;
1780 	}
1781 	/*
1782 	 * Check for the editing character. If the display width of
1783 	 * the last byte at the canonical buffer is not one and also
1784 	 * smaller than or equal to UNKNOWN_WIDTH, the character at
1785 	 * the end of the buffer is a multi-byte and/or multi-column
1786 	 * character.
1787 	 */
1788 	if (c == tp->t_modes.c_cc[VERASE] || c == tp->t_modes.c_cc[VERASE2]) {
1789 		if (tp->t_state & TS_QUOT) {
1790 			/*
1791 			 * Get rid of the backslash, and put the
1792 			 * erase character in its place.
1793 			 */
1794 			ldterm_erase(wrq, ebsize, tp);
1795 			bpt = tp->t_endmsg;
1796 			goto escaped;
1797 		} else {
1798 			if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
1799 			    (*(tp->t_eucp - 1) != 1 &&
1800 			    *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
1801 				ldterm_csi_erase(wrq, ebsize, tp);
1802 			else
1803 				ldterm_erase(wrq, ebsize, tp);
1804 			bpt = tp->t_endmsg;
1805 			goto out;
1806 		}
1807 	}
1808 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
1809 		/*
1810 		 * Do "ASCII word" or "multibyte character token/chunk" erase.
1811 		 */
1812 		if (tp->t_state & TS_MEUC)
1813 			ldterm_csi_werase(wrq, ebsize, tp);
1814 		else
1815 			ldterm_werase(wrq, ebsize, tp);
1816 		bpt = tp->t_endmsg;
1817 		goto out;
1818 	}
1819 	if (c == tp->t_modes.c_cc[VKILL]) {
1820 		if (tp->t_state & TS_QUOT) {
1821 			/*
1822 			 * Get rid of the backslash, and put the kill
1823 			 * character in its place.
1824 			 */
1825 			ldterm_erase(wrq, ebsize, tp);
1826 			bpt = tp->t_endmsg;
1827 			goto escaped;
1828 		} else {
1829 			ldterm_kill(wrq, ebsize, tp);
1830 			bpt = tp->t_endmsg;
1831 			goto out;
1832 		}
1833 	}
1834 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
1835 		ldterm_reprint(wrq, ebsize, tp);
1836 		goto out;
1837 	}
1838 	/*
1839 	 * If the preceding character was a backslash: if the current
1840 	 * character is an EOF, get rid of the backslash and treat
1841 	 * the EOF as data; if we're in XCASE mode and the current
1842 	 * character is part of a backslash-X escape sequence,
1843 	 * process it; otherwise, just treat the current character
1844 	 * normally.
1845 	 */
1846 	if (tp->t_state & TS_QUOT) {
1847 		tp->t_state &= ~TS_QUOT;
1848 		if (c == tp->t_modes.c_cc[VEOF]) {
1849 			/*
1850 			 * EOF character. Since it's escaped, get rid
1851 			 * of the backslash and put the EOF character
1852 			 * in its place.
1853 			 */
1854 			ldterm_erase(wrq, ebsize, tp);
1855 			bpt = tp->t_endmsg;
1856 		} else {
1857 			/*
1858 			 * If we're in XCASE mode, and the current
1859 			 * character is part of a backslash-X
1860 			 * sequence, get rid of the backslash and
1861 			 * replace the current character with what
1862 			 * that sequence maps to.
1863 			 */
1864 			if ((tp->t_modes.c_lflag & XCASE) &&
1865 			    imaptab[c] != '\0') {
1866 				ldterm_erase(wrq, ebsize, tp);
1867 				bpt = tp->t_endmsg;
1868 				c = imaptab[c];
1869 			}
1870 		}
1871 	} else {
1872 		/*
1873 		 * Previous character wasn't backslash; check whether
1874 		 * this was the EOF character.
1875 		 */
1876 		if (c == tp->t_modes.c_cc[VEOF]) {
1877 			/*
1878 			 * EOF character. Don't echo it unless
1879 			 * ECHOCTL is set, don't stuff it in the
1880 			 * current line, but send the line up the
1881 			 * stream.
1882 			 */
1883 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
1884 			    (tp->t_modes.c_lflag & IEXTEN) &&
1885 			    (tp->t_modes.c_lflag & ECHO)) {
1886 				i = ldterm_echo(c, wrq, ebsize, tp);
1887 				while (i > 0) {
1888 					ldterm_outchar('\b', wrq, ebsize, tp);
1889 					i--;
1890 				}
1891 			}
1892 			bpt->b_datap->db_type = M_DATA;
1893 			ldterm_msg_upstream(q, tp);
1894 			if (!canputnext(q)) {
1895 				bpt = NULL;
1896 				*dofreep = 0;
1897 			} else {
1898 				bpt = newmsg(tp);
1899 				*dofreep = 1;
1900 			}
1901 			goto out;
1902 		}
1903 	}
1904 
1905 escaped:
1906 	/*
1907 	 * First, make sure we can fit one WHOLE multi-byte char in the
1908 	 * buffer.  This is one place where we have overhead even if
1909 	 * not in multi-byte mode; the overhead is subtracting
1910 	 * tp->t_maxeuc from MAX_CANON before checking.
1911 	 *
1912 	 * Allows MAX_CANON bytes in the buffer before throwing awaying
1913 	 * the the overflow of characters.
1914 	 */
1915 	if ((tp->t_msglen > ((_TTY_BUFSIZ + 1) - (int)tp->t_maxeuc)) &&
1916 	    !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
1917 
1918 		/*
1919 		 * Byte will cause line to overflow, or the next EUC
1920 		 * won't fit: Ring the bell or discard all input, and
1921 		 * don't save the byte away.
1922 		 */
1923 		if (tp->t_modes.c_iflag & IMAXBEL) {
1924 			if (canputnext(wrq))
1925 				ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
1926 			goto out;
1927 		} else {
1928 			/*
1929 			 * MAX_CANON processing. free everything in
1930 			 * the current line and start with the
1931 			 * current character as the first character.
1932 			 */
1933 			DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
1934 			freemsg(tp->t_message);
1935 			tp->t_message = NULL;
1936 			tp->t_endmsg = NULL;
1937 			tp->t_msglen = 0;
1938 			tp->t_rocount = 0;	/* if it hasn't been type */
1939 			tp->t_rocol = 0;	/* it hasn't been echoed :-) */
1940 			if (tp->t_state & TS_MEUC) {
1941 				ASSERT(tp->t_eucp_mp);
1942 				tp->t_eucp = tp->t_eucp_mp->b_rptr;
1943 			}
1944 			tp->t_state &= ~TS_SLNCH;
1945 			bpt = newmsg(tp);
1946 		}
1947 	}
1948 	/*
1949 	 * Add the character to the current line.
1950 	 */
1951 	if (bpt->b_wptr >= bpt->b_datap->db_lim) {
1952 		/*
1953 		 * No more room in this mblk; save this one away, and
1954 		 * allocate a new one.
1955 		 */
1956 		bpt->b_datap->db_type = M_DATA;
1957 		if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
1958 			goto out;
1959 
1960 		/*
1961 		 * Chain the new one to the end of the old one, and
1962 		 * mark it as the last block in the current line.
1963 		 */
1964 		tp->t_endmsg->b_cont = bpt;
1965 		tp->t_endmsg = bpt;
1966 	}
1967 	*bpt->b_wptr++ = c;
1968 	tp->t_msglen++;		/* message length in BYTES */
1969 
1970 	/*
1971 	 * In multi-byte mode, we have to keep track of where we are.
1972 	 * The first bytes of multi-byte chars get the full count for the
1973 	 * whole character.  We don't do any column calculations
1974 	 * here, but we need the information for when we do. We could
1975 	 * come across cases where we are getting garbage on the
1976 	 * line, but we're in multi-byte mode.  In that case, we may
1977 	 * see ASCII controls come in the middle of what should have been a
1978 	 * multi-byte character.  Call ldterm_eucwarn...eventually, a
1979 	 * warning message will be printed about it.
1980 	 */
1981 	if (tp->t_state & TS_MEUC) {
1982 		if (tp->t_eucleft) {	/* if in a multi-byte char already */
1983 			--tp->t_eucleft;
1984 			*tp->t_eucp++ = 0;	/* is a subsequent byte */
1985 			if (c < (uchar_t)0x20)
1986 				ldterm_eucwarn(tp);
1987 		} else { /* is the first byte of a multi-byte, or is ASCII */
1988 			if (ISASCII(c)) {
1989 				*tp->t_eucp++ =
1990 				    tp->t_csmethods.ldterm_dispwidth(c,
1991 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
1992 				tp->t_codeset = 0;
1993 			} else {
1994 				*tp->t_eucp++ =
1995 				    tp->t_csmethods.ldterm_dispwidth(c,
1996 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
1997 				tp->t_eucleft =
1998 				    tp->t_csmethods.ldterm_memwidth(c,
1999 				    (void *)tp) - 1;
2000 				tp->t_codeset = ldterm_codeset(
2001 				    tp->t_csdata.codeset_type, c);
2002 			}
2003 		}
2004 	}
2005 	/*
2006 	 * AT&T is concerned about the following but we aren't since
2007 	 * we have already shipped code that works.
2008 	 *
2009 	 * EOL2/XCASE should be conditioned with IEXTEN to be truly
2010 	 * POSIX conformant. This is going to cause problems for
2011 	 * pre-SVR4.0 programs that don't know about IEXTEN. Hence
2012 	 * EOL2/IEXTEN is not conditioned with IEXTEN.
2013 	 */
2014 	if (!(tp->t_state & TS_SLNCH) &&
2015 	    (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
2016 	    (c == tp->t_modes.c_cc[VEOL2]))))) {
2017 		/*
2018 		 * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
2019 		 * tp->t_modes.c_cc[VEOL2]))))) {
2020 		 */
2021 		/*
2022 		 * It's a line-termination character; send the line
2023 		 * up the stream.
2024 		 */
2025 		bpt->b_datap->db_type = M_DATA;
2026 		ldterm_msg_upstream(q, tp);
2027 		if (tp->t_state & TS_MEUC) {
2028 			ASSERT(tp->t_eucp_mp);
2029 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
2030 		}
2031 		if ((bpt = newmsg(tp)) == NULL)
2032 			goto out;
2033 	} else {
2034 		/*
2035 		 * Character was escaped with LNEXT.
2036 		 */
2037 		if (tp->t_rocount++ == 0)
2038 			tp->t_rocol = tp->t_col;
2039 		tp->t_state &= ~(TS_SLNCH|TS_QUOT);
2040 		/*
2041 		 * If the current character is a single byte and single
2042 		 * column character and it is the backslash character and
2043 		 * IEXTEN, then the state will have TS_QUOT.
2044 		 */
2045 		if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
2046 		    (!(tp->t_state & TS_MEUC) ||
2047 		    ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
2048 			tp->t_state |= TS_QUOT;
2049 	}
2050 
2051 	/*
2052 	 * Echo it.
2053 	 */
2054 	if (tp->t_state & TS_ERASE) {
2055 		tp->t_state &= ~TS_ERASE;
2056 		if (tp->t_modes.c_lflag & ECHO)
2057 			ldterm_outchar('/', wrq, ebsize, tp);
2058 	}
2059 	if (tp->t_modes.c_lflag & ECHO)
2060 		(void) ldterm_echo(c, wrq, ebsize, tp);
2061 	else {
2062 		/*
2063 		 * Echo NL when ECHO turned off, if ECHONL flag is
2064 		 * set.
2065 		 */
2066 		if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
2067 			ldterm_outchar(c, wrq, ebsize, tp);
2068 	}
2069 
2070 out:
2071 
2072 	return (bpt);
2073 }
2074 
2075 
2076 static int
ldterm_unget(ldtermstd_state_t * tp)2077 ldterm_unget(ldtermstd_state_t *tp)
2078 {
2079 	mblk_t *bpt;
2080 
2081 	if ((bpt = tp->t_endmsg) == NULL)
2082 		return (-1);	/* no buffers */
2083 	if (bpt->b_rptr == bpt->b_wptr)
2084 		return (-1);	/* zero-length record */
2085 	tp->t_msglen--;		/* one fewer character */
2086 	return (*--bpt->b_wptr);
2087 }
2088 
2089 
2090 static void
ldterm_trim(ldtermstd_state_t * tp)2091 ldterm_trim(ldtermstd_state_t *tp)
2092 {
2093 	mblk_t *bpt;
2094 	mblk_t *bp;
2095 
2096 	ASSERT(tp->t_endmsg);
2097 	bpt = tp->t_endmsg;
2098 
2099 	if (bpt->b_rptr == bpt->b_wptr) {
2100 		/*
2101 		 * This mblk is now empty. Find the previous mblk;
2102 		 * throw this one away, unless it's the first one.
2103 		 */
2104 		bp = tp->t_message;
2105 		if (bp != bpt) {
2106 			while (bp->b_cont != bpt) {
2107 				ASSERT(bp->b_cont);
2108 				bp = bp->b_cont;
2109 			}
2110 			bp->b_cont = NULL;
2111 			freeb(bpt);
2112 			tp->t_endmsg = bp;	/* point to that mblk */
2113 		}
2114 	}
2115 }
2116 
2117 
2118 /*
2119  * Rubout one character from the current line being built for tp as
2120  * cleanly as possible.  q is the write queue for tp. Most of this
2121  * can't be applied to multi-byte processing.  We do our own thing
2122  * for that... See the "ldterm_eucerase" routine.  We never call
2123  * ldterm_rubout on a multi-byte or multi-column character.
2124  */
2125 static void
ldterm_rubout(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2126 ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2127 {
2128 	int tabcols;
2129 	static unsigned char crtrubout[] = "\b \b\b \b";
2130 #define	RUBOUT1	&crtrubout[3]	/* rub out one position */
2131 #define	RUBOUT2	&crtrubout[0]	/* rub out two positions */
2132 
2133 	if (!(tp->t_modes.c_lflag & ECHO))
2134 		return;
2135 	if (tp->t_modes.c_lflag & ECHOE) {
2136 		/*
2137 		 * "CRT rubout"; try erasing it from the screen.
2138 		 */
2139 		if (tp->t_rocount == 0) {
2140 			/*
2141 			 * After the character being erased was
2142 			 * echoed, some data was written to the
2143 			 * terminal; we can't erase it cleanly, so we
2144 			 * just reprint the whole line as if the user
2145 			 * had typed the reprint character.
2146 			 */
2147 			ldterm_reprint(q, ebsize, tp);
2148 			return;
2149 		} else {
2150 			/*
2151 			 * XXX what about escaped characters?
2152 			 */
2153 			switch (typetab[c]) {
2154 
2155 			case ORDINARY:
2156 				if ((tp->t_modes.c_lflag & XCASE) &&
2157 				    omaptab[c])
2158 					ldterm_outstring(RUBOUT1, 3, q, ebsize,
2159 					    tp);
2160 				ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
2161 				break;
2162 
2163 			case VTAB:
2164 			case BACKSPACE:
2165 			case CONTROL:
2166 			case RETURN:
2167 			case NEWLINE:
2168 				if ((tp->t_modes.c_lflag & ECHOCTL) &&
2169 				    (tp->t_modes.c_lflag & IEXTEN))
2170 					ldterm_outstring(RUBOUT2, 6, q, ebsize,
2171 					    tp);
2172 				break;
2173 
2174 			case TAB:
2175 				if (tp->t_rocount < tp->t_msglen) {
2176 					/*
2177 					 * While the tab being erased was
2178 					 * expanded, some data was written
2179 					 * to the terminal; we can't erase
2180 					 * it cleanly, so we just reprint
2181 					 * the whole line as if the user
2182 					 * had typed the reprint character.
2183 					 */
2184 					ldterm_reprint(q, ebsize, tp);
2185 					return;
2186 				}
2187 				tabcols = ldterm_tabcols(tp);
2188 				while (--tabcols >= 0)
2189 					ldterm_outchar('\b', q, ebsize, tp);
2190 				break;
2191 			}
2192 		}
2193 	} else if ((tp->t_modes.c_lflag & ECHOPRT) &&
2194 	    (tp->t_modes.c_lflag & IEXTEN)) {
2195 		/*
2196 		 * "Printing rubout"; echo it between \ and /.
2197 		 */
2198 		if (!(tp->t_state & TS_ERASE)) {
2199 			ldterm_outchar('\\', q, ebsize, tp);
2200 			tp->t_state |= TS_ERASE;
2201 		}
2202 		(void) ldterm_echo(c, q, ebsize, tp);
2203 	} else
2204 		(void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
2205 	tp->t_rocount--;	/* we "unechoed" this character */
2206 }
2207 
2208 
2209 /*
2210  * Find the number of characters the tab we just deleted took up by
2211  * zipping through the current line and recomputing the column
2212  * number.
2213  */
2214 static int
ldterm_tabcols(ldtermstd_state_t * tp)2215 ldterm_tabcols(ldtermstd_state_t *tp)
2216 {
2217 	int col;
2218 	int i;
2219 	mblk_t *bp;
2220 	unsigned char *readp, *endp;
2221 	unsigned char c;
2222 	uchar_t *startp;
2223 	char errflg;
2224 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2225 
2226 	col = tp->t_rocol;
2227 	/*
2228 	 * If we're doing multi-byte stuff, zip through the list of
2229 	 * widths to figure out where we are (we've kept track in most
2230 	 * cases).
2231 	 */
2232 	if (tp->t_state & TS_MEUC) {
2233 		ASSERT(tp->t_eucp_mp);
2234 		bp = tp->t_message;
2235 		startp = bp->b_datap->db_base;
2236 		readp = tp->t_eucp_mp->b_rptr;
2237 		endp = tp->t_eucp;
2238 		errflg = (char)0;
2239 		while (readp < endp) {
2240 			switch (*readp) {
2241 			case EUC_TWIDTH:	/* it's a tab */
2242 				col |= 07;	/* bump up */
2243 				col++;
2244 				break;
2245 			case EUC_BSWIDTH:	/* backspace */
2246 				if (col)
2247 					col--;
2248 				break;
2249 			case EUC_NLWIDTH:	/* newline */
2250 				if (tp->t_modes.c_oflag & ONLRET)
2251 					col = 0;
2252 				break;
2253 			case EUC_CRWIDTH:	/* return */
2254 				col = 0;
2255 				break;
2256 			case UNKNOWN_WIDTH:	/* UTF-8 unknown width */
2257 				if (tp->t_csdata.codeset_type !=
2258 				    LDTERM_CS_TYPE_UTF8 || errflg) {
2259 					*readp = 1;
2260 					col++;
2261 					break;
2262 				}
2263 				/*
2264 				 * Collect the current UTF-8 character bytes
2265 				 * from (possibly multiple) data buffers so
2266 				 * that we can figure out the display width.
2267 				 */
2268 				u8[0] = *startp;
2269 				for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
2270 				    (*(readp + i) == 0); i++) {
2271 					startp++;
2272 					if (startp >= bp->b_datap->db_lim) {
2273 						if (bp->b_cont) {
2274 							bp = bp->b_cont;
2275 							startp =
2276 							    bp->b_datap->
2277 							    db_base;
2278 						} else {
2279 							*readp = 1;
2280 							col++;
2281 							break;
2282 						}
2283 					}
2284 					u8[i] = *startp;
2285 				}
2286 
2287 				/* tp->t_eucp_mp contains wrong info?? */
2288 				if (*readp == 1)
2289 					break;
2290 
2291 				*readp = ldterm_utf8_width(u8, i);
2292 
2293 				col += *readp;
2294 				readp += (i - 1);
2295 				break;
2296 			default:
2297 				col += *readp;
2298 				break;
2299 			}
2300 			++readp;
2301 			++startp;
2302 			if (startp >= bp->b_datap->db_lim) {
2303 				if (bp->b_cont) {
2304 					bp = bp->b_cont;
2305 					startp = bp->b_datap->db_base;
2306 				} else {
2307 					/*
2308 					 * This will happen only if
2309 					 * tp->t_eucp_mp contains wrong
2310 					 * display width info.
2311 					 */
2312 					errflg = (char)1;
2313 					startp--;
2314 				}
2315 			}
2316 		}
2317 		goto eucout;	/* finished! */
2318 	}
2319 	bp = tp->t_message;
2320 	do {
2321 		readp = bp->b_rptr;
2322 		while (readp < bp->b_wptr) {
2323 			c = *readp++;
2324 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
2325 			    (tp->t_modes.c_lflag & IEXTEN)) {
2326 				if (c <= 037 && c != '\t' && c != '\n' ||
2327 				    c == 0177) {
2328 					col += 2;
2329 					continue;
2330 				}
2331 			}
2332 			/*
2333 			 * Column position calculated here.
2334 			 */
2335 			switch (typetab[c]) {
2336 
2337 				/*
2338 				 * Ordinary characters; advance by
2339 				 * one.
2340 				 */
2341 			case ORDINARY:
2342 				col++;
2343 				break;
2344 
2345 				/*
2346 				 * Non-printing characters; nothing
2347 				 * happens.
2348 				 */
2349 			case CONTROL:
2350 				break;
2351 
2352 				/* Backspace */
2353 			case BACKSPACE:
2354 				if (col != 0)
2355 					col--;
2356 				break;
2357 
2358 				/* Newline; column depends on flags. */
2359 			case NEWLINE:
2360 				if (tp->t_modes.c_oflag & ONLRET)
2361 					col = 0;
2362 				break;
2363 
2364 				/* tab */
2365 			case TAB:
2366 				col |= 07;
2367 				col++;
2368 				break;
2369 
2370 				/* vertical motion */
2371 			case VTAB:
2372 				break;
2373 
2374 				/* carriage return */
2375 			case RETURN:
2376 				col = 0;
2377 				break;
2378 			}
2379 		}
2380 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
2381 
2382 	/*
2383 	 * "col" is now the column number before the tab. "tp->t_col"
2384 	 * is still the column number after the tab, since we haven't
2385 	 * erased the tab yet. Thus "tp->t_col - col" is the number
2386 	 * of positions the tab moved.
2387 	 */
2388 eucout:
2389 	col = tp->t_col - col;
2390 	if (col > 8)
2391 		col = 8;	/* overflow screw */
2392 	return (col);
2393 }
2394 
2395 
2396 /*
2397  * Erase a single character; We ONLY ONLY deal with ASCII or
2398  * single-column single-byte codeset character.  For multi-byte characters,
2399  * see "ldterm_csi_erase".
2400  */
2401 static void
ldterm_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2402 ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2403 {
2404 	int c;
2405 
2406 	if ((c = ldterm_unget(tp)) != -1) {
2407 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2408 		ldterm_trim(tp);
2409 		if (tp->t_state & TS_MEUC)
2410 			--tp->t_eucp;
2411 	}
2412 }
2413 
2414 
2415 /*
2416  * Erase an entire word, single-byte EUC only please.
2417  */
2418 static void
ldterm_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2419 ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2420 {
2421 	int c;
2422 
2423 	/*
2424 	 * Erase trailing white space, if any.
2425 	 */
2426 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2427 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2428 		ldterm_trim(tp);
2429 	}
2430 
2431 	/*
2432 	 * Erase non-white-space characters, if any.
2433 	 */
2434 	while (c != -1 && c != ' ' && c != '\t') {
2435 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2436 		ldterm_trim(tp);
2437 		c = ldterm_unget(tp);
2438 	}
2439 	if (c != -1) {
2440 		/*
2441 		 * We removed one too many characters; put the last
2442 		 * one back.
2443 		 */
2444 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
2445 		tp->t_msglen++;
2446 	}
2447 }
2448 
2449 
2450 /*
2451  * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
2452  * "Word erase" only makes sense in languages which space between words,
2453  * and it's presumptuous for us to attempt "word erase" when we don't
2454  * know anything about what's really going on.  It makes no sense for
2455  * many languages, as the criteria for defining words and tokens may
2456  * be completely different.
2457  *
2458  * In the TS_MEUC case (which is how we got here), we define a token to
2459  * be space- or tab-delimited, and erase one of them.  It helps to
2460  * have this for command lines, but it's otherwise useless for text
2461  * editing applications; you need more sophistication than we can
2462  * provide here.
2463  */
2464 static void
ldterm_csi_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2465 ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2466 {
2467 	int c, i;
2468 	int len;
2469 	uchar_t *ip;
2470 	uchar_t	u8[LDTERM_CS_MAX_BYTE_LENGTH];
2471 	uchar_t	u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2472 
2473 	/*
2474 	 * ip points to the width of the actual bytes.  t_eucp points
2475 	 * one byte beyond, where the next thing will be inserted.
2476 	 */
2477 	ip = tp->t_eucp - 1;
2478 	/*
2479 	 * Erase trailing white space, if any.
2480 	 */
2481 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2482 		tp->t_eucp--;
2483 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2484 		ldterm_trim(tp);
2485 		--ip;
2486 	}
2487 
2488 	/*
2489 	 * Erase non-white-space characters, if any.  The outer loop
2490 	 * bops through each byte in the buffer. Multi-byte is removed, as
2491 	 * is ASCII, one byte at a time. The inner loop (for) is only
2492 	 * executed for first bytes of multi-byte.  The inner loop erases
2493 	 * the number of columns required for the multi-byte char.  We check
2494 	 * for ASCII first, and ldterm_rubout knows about ASCII.
2495 	 */
2496 	len = 0;
2497 	while (c != -1 && c != ' ' && c != '\t') {
2498 		tp->t_eucp--;
2499 		if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2500 			u8[len++] = (uchar_t)c;
2501 		}
2502 		/*
2503 		 * Unlike EUC, except the leading byte, some bytes of
2504 		 * a non-EUC multi-byte characters are in the ASCII code
2505 		 * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
2506 		 * ISASCII().
2507 		 * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
2508 		 * will ensure that it is a single byte character (even though
2509 		 * it is on display width not byte length) and can be further
2510 		 * checked whether it is an ASCII character or not.
2511 		 *
2512 		 * When ECHOCTL is on and 'c' is an ASCII control character,
2513 		 * *ip == 2 happens.
2514 		 */
2515 		if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
2516 		    ISASCII(c)) {
2517 			ldterm_rubout((unsigned char) c, q, ebsize, tp);
2518 			len = 0;
2519 		} else if (*ip) {
2520 			if (*ip == UNKNOWN_WIDTH) {
2521 				if (tp->t_csdata.codeset_type ==
2522 				    LDTERM_CS_TYPE_UTF8) {
2523 					for (i = 0; i < len; i++)
2524 						u8_2[i] = u8[len - i - 1];
2525 					*ip = ldterm_utf8_width(u8_2, len);
2526 				} else {
2527 					*ip = 1;
2528 				}
2529 			}
2530 			/*
2531 			 * erase for number of columns required for
2532 			 * this multi-byte character. Hopefully, matches
2533 			 * ldterm_dispwidth!
2534 			 */
2535 			for (i = 0; i < (int)*ip; i++)
2536 				ldterm_rubout(' ', q, ebsize, tp);
2537 			len = 0;
2538 		}
2539 		ldterm_trim(tp);
2540 		--ip;
2541 		c = ldterm_unget(tp);
2542 	}
2543 	if (c != -1) {
2544 		/*
2545 		 * We removed one too many characters; put the last
2546 		 * one back.
2547 		 */
2548 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
2549 		tp->t_msglen++;
2550 	}
2551 }
2552 
2553 
2554 /*
2555  * Kill an entire line, erasing each character one-by-one (if ECHOKE
2556  * is set) or just echoing the kill character, followed by a newline
2557  * (if ECHOK is set).  Multi-byte processing is included here.
2558  */
2559 
2560 static void
ldterm_kill(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2561 ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2562 {
2563 	int c, i;
2564 	int len;
2565 	uchar_t *ip;
2566 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2567 	uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2568 
2569 	if ((tp->t_modes.c_lflag & ECHOKE) &&
2570 	    (tp->t_modes.c_lflag & IEXTEN) &&
2571 	    (tp->t_msglen == tp->t_rocount)) {
2572 		if (tp->t_state & TS_MEUC) {
2573 			ip = tp->t_eucp - 1;
2574 			/*
2575 			 * This loop similar to "ldterm_csi_werase" above.
2576 			 */
2577 			len = 0;
2578 			while ((c = ldterm_unget(tp)) != (-1)) {
2579 				tp->t_eucp--;
2580 				if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2581 					u8[len++] = (uchar_t)c;
2582 				}
2583 				if ((*ip == 1 || *ip == 2 ||
2584 				    *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
2585 					ldterm_rubout((unsigned char) c, q,
2586 					    ebsize, tp);
2587 					len = 0;
2588 				} else if (*ip) {
2589 					if (*ip == UNKNOWN_WIDTH) {
2590 						if (tp->t_csdata.codeset_type
2591 						    == LDTERM_CS_TYPE_UTF8) {
2592 							for (i = 0; i < len;
2593 							    i++)
2594 								u8_2[i] =
2595 								    u8[len-i-1];
2596 							*ip = ldterm_utf8_width(
2597 							    u8_2, len);
2598 						} else {
2599 							*ip = 1;
2600 						}
2601 					}
2602 					for (i = 0; i < (int)*ip; i++)
2603 						ldterm_rubout(' ', q, ebsize,
2604 						    tp);
2605 					len = 0;
2606 				}
2607 				ldterm_trim(tp);
2608 				--ip;
2609 			}
2610 		} else {
2611 			while ((c = ldterm_unget(tp)) != -1) {
2612 				ldterm_rubout((unsigned char) c, q, ebsize, tp);
2613 				ldterm_trim(tp);
2614 			}
2615 		}
2616 	} else {
2617 		(void) ldterm_echo(tp->t_modes.c_cc[VKILL], q, ebsize, tp);
2618 		if (tp->t_modes.c_lflag & ECHOK)
2619 			(void) ldterm_echo('\n', q, ebsize, tp);
2620 		while (ldterm_unget(tp) != -1) {
2621 			if (tp->t_state & TS_MEUC)
2622 				--tp->t_eucp;
2623 			ldterm_trim(tp);
2624 		}
2625 		tp->t_rocount = 0;
2626 		if (tp->t_state & TS_MEUC)
2627 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
2628 	}
2629 	tp->t_state &= ~(TS_QUOT|TS_ERASE|TS_SLNCH);
2630 }
2631 
2632 
2633 /*
2634  * Reprint the current input line. We assume c_cc has already been
2635  * checked. XXX just the current line, not the whole queue? What
2636  * about DEFECHO mode?
2637  */
2638 static void
ldterm_reprint(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2639 ldterm_reprint(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2640 {
2641 	mblk_t *bp;
2642 	unsigned char *readp;
2643 
2644 	if (tp->t_modes.c_cc[VREPRINT] != (unsigned char) 0)
2645 		(void) ldterm_echo(tp->t_modes.c_cc[VREPRINT], q, ebsize, tp);
2646 	ldterm_outchar('\n', q, ebsize, tp);
2647 
2648 	bp = tp->t_message;
2649 	do {
2650 		readp = bp->b_rptr;
2651 		while (readp < bp->b_wptr)
2652 			(void) ldterm_echo(*readp++, q, ebsize, tp);
2653 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
2654 
2655 	tp->t_state &= ~TS_ERASE;
2656 	tp->t_rocount = tp->t_msglen;	/* we reechoed the entire line */
2657 	tp->t_rocol = 0;
2658 }
2659 
2660 
2661 /*
2662  * Non canonical processing. Called with q locked from  ldtermrsrv.
2663  *
2664  */
2665 static mblk_t *
ldterm_dononcanon(mblk_t * bp,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp)2666 ldterm_dononcanon(mblk_t *bp, mblk_t *bpt, size_t ebsize, queue_t *q,
2667     ldtermstd_state_t *tp)
2668 {
2669 	queue_t *wrq = WR(q);
2670 	unsigned char *rptr;
2671 	size_t bytes_in_bp;
2672 	size_t roomleft;
2673 	size_t bytes_to_move;
2674 	int free_flag = 0;
2675 
2676 	if (tp->t_modes.c_lflag & (ECHO|ECHONL|IEXTEN)) {
2677 		unsigned char *wptr;
2678 		unsigned char c;
2679 
2680 		/*
2681 		 * Either we must echo the characters, or we must
2682 		 * echo NL, or we must check for VLNEXT. Process
2683 		 * characters one at a time.
2684 		 */
2685 		rptr = bp->b_rptr;
2686 		wptr = bp->b_rptr;
2687 		while (rptr < bp->b_wptr) {
2688 			c = *rptr++;
2689 			/*
2690 			 * If this character is the literal next
2691 			 * character, echo it as '^' and backspace
2692 			 * over it if echoing is enabled, indicate
2693 			 * that the next character is to be treated
2694 			 * literally, and remove the LNEXT from the
2695 			 * input stream.
2696 			 *
2697 			 * If the *previous* character was the literal
2698 			 * next character, don't check whether this
2699 			 * is a literal next or not.
2700 			 */
2701 			if ((tp->t_modes.c_lflag & IEXTEN) &&
2702 			    !(tp->t_state & TS_SLNCH) &&
2703 			    c != _POSIX_VDISABLE &&
2704 			    c == tp->t_modes.c_cc[VLNEXT]) {
2705 				if (tp->t_modes.c_lflag & ECHO)
2706 					ldterm_outstring(
2707 					    (unsigned char *)"^\b",
2708 					    2, wrq, ebsize, tp);
2709 				tp->t_state |= TS_SLNCH;
2710 				continue;	/* and ignore it */
2711 			}
2712 			/*
2713 			 * Not a "literal next" character, so it
2714 			 * should show up as input. If it was
2715 			 * literal-nexted, turn off the literal-next
2716 			 * flag.
2717 			 */
2718 			tp->t_state &= ~TS_SLNCH;
2719 			*wptr++ = c;
2720 			if (tp->t_modes.c_lflag & ECHO) {
2721 				/*
2722 				 * Echo the character.
2723 				 */
2724 				(void) ldterm_echo(c, wrq, ebsize, tp);
2725 			} else if (tp->t_modes.c_lflag & ECHONL) {
2726 				/*
2727 				 * Echo NL, even though ECHO is not
2728 				 * set.
2729 				 */
2730 				if (c == '\n')
2731 					ldterm_outchar('\n', wrq, 1, tp);
2732 			}
2733 		}
2734 		bp->b_wptr = wptr;
2735 	} else {
2736 		/*
2737 		 * If there are any characters in this buffer, and
2738 		 * the first of them was literal-nexted, turn off the
2739 		 * literal-next flag.
2740 		 */
2741 		if (bp->b_rptr != bp->b_wptr)
2742 			tp->t_state &= ~TS_SLNCH;
2743 	}
2744 
2745 	ASSERT(bp->b_wptr >= bp->b_rptr);
2746 	bytes_in_bp = bp->b_wptr - bp->b_rptr;
2747 	rptr = bp->b_rptr;
2748 	while (bytes_in_bp != 0) {
2749 		roomleft = bpt->b_datap->db_lim - bpt->b_wptr;
2750 		if (roomleft == 0) {
2751 			/*
2752 			 * No more room in this mblk; save this one
2753 			 * away, and allocate a new one.
2754 			 */
2755 			if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL) {
2756 				freeb(bp);
2757 				DEBUG4(("ldterm_do_noncanon: allcob failed\n"));
2758 				return (bpt);
2759 			}
2760 			/*
2761 			 * Chain the new one to the end of the old
2762 			 * one, and mark it as the last block in the
2763 			 * current lump.
2764 			 */
2765 			tp->t_endmsg->b_cont = bpt;
2766 			tp->t_endmsg = bpt;
2767 			roomleft = IBSIZE;
2768 		}
2769 		DEBUG5(("roomleft=%d, bytes_in_bp=%d, tp->t_rd_request=%d\n",
2770 		    roomleft, bytes_in_bp, tp->t_rd_request));
2771 		/*
2772 		 * if there is a read pending before this data got
2773 		 * here move bytes according to the minimum of room
2774 		 * left in this buffer, bytes in the message and byte
2775 		 * count requested in the read. If there is no read
2776 		 * pending, move the minimum of the first two
2777 		 */
2778 		if (tp->t_rd_request == 0)
2779 			bytes_to_move = MIN(roomleft, bytes_in_bp);
2780 		else
2781 			bytes_to_move =
2782 			    MIN(MIN(roomleft, bytes_in_bp), tp->t_rd_request);
2783 		DEBUG5(("Bytes to move = %lu\n", bytes_to_move));
2784 		if (bytes_to_move == 0)
2785 			break;
2786 		bcopy(rptr, bpt->b_wptr, bytes_to_move);
2787 		bpt->b_wptr += bytes_to_move;
2788 		rptr += bytes_to_move;
2789 		tp->t_msglen += bytes_to_move;
2790 		bytes_in_bp -= bytes_to_move;
2791 	}
2792 	if (bytes_in_bp == 0) {
2793 		DEBUG4(("bytes_in_bp is zero\n"));
2794 		freeb(bp);
2795 	} else
2796 		free_flag = 1;	/* for debugging olny */
2797 
2798 	DEBUG4(("ldterm_do_noncanon: VMIN = %d, VTIME = %d, msglen = %d, \
2799 		tid = %d\n", V_MIN, V_TIME, tp->t_msglen, tp->t_vtid));
2800 	/*
2801 	 * If there is a pending read request at the stream head we
2802 	 * need to do VMIN/VTIME processing. The four possible cases
2803 	 * are:
2804 	 *	MIN = 0, TIME > 0
2805 	 *	MIN = >, TIME = 0
2806 	 *	MIN > 0, TIME > 0
2807 	 *	MIN = 0, TIME = 0
2808 	 * If we can satisfy VMIN, send it up, and start a new
2809 	 * timer if necessary.  These four cases of VMIN/VTIME
2810 	 * are also dealt with in the write side put routine
2811 	 * when the M_READ is first seen.
2812 	 */
2813 
2814 	DEBUG4(("Incoming data while M_READ'ing\n"));
2815 	/*
2816 	 * Case 1:  Any data will satisfy the read, so send
2817 	 * it upstream.
2818 	 */
2819 	if (V_MIN == 0 && V_TIME > 0) {
2820 		if (tp->t_msglen)
2821 			vmin_satisfied(q, tp, 1);
2822 		else {
2823 			/* EMPTY */
2824 			DEBUG4(("ldterm_do_noncanon called, but no data!\n"));
2825 		}
2826 		/*
2827 		 * Case 2:  This should never time out, so
2828 		 * until there's enough data, do nothing.
2829 		 */
2830 	} else if (V_MIN > 0 && V_TIME == 0) {
2831 		if (tp->t_msglen >= (int)V_MIN)
2832 			vmin_satisfied(q, tp, 1);
2833 
2834 		/*
2835 		 * Case 3:  If MIN is satisfied, send it up.
2836 		 * Also, remember to start a new timer *every*
2837 		 * time we see something if MIN isn't
2838 		 * safisfied
2839 		 */
2840 	} else if (V_MIN > 0 && V_TIME > 0) {
2841 		if (tp->t_msglen >= (int)V_MIN)
2842 			vmin_satisfied(q, tp, 1);
2843 		else
2844 			vmin_settimer(q);
2845 		/*
2846 		 * Case 4:  Not possible.  This request
2847 		 * should always be satisfied from the write
2848 		 * side, left here for debugging.
2849 		 */
2850 	} else {	/* V_MIN == 0 && V_TIME == 0 */
2851 			vmin_satisfied(q, tp, 1);
2852 	}
2853 
2854 	if (free_flag) {
2855 		/* EMPTY */
2856 		DEBUG4(("CAUTION message block not freed\n"));
2857 	}
2858 	return (newmsg(tp));
2859 }
2860 
2861 
2862 /*
2863  * Echo a typed byte to the terminal.  Returns the number of bytes
2864  * printed. Bytes of EUC characters drop through the ECHOCTL stuff
2865  * and are just output as themselves.
2866  */
2867 static int
ldterm_echo(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2868 ldterm_echo(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2869 {
2870 	int i;
2871 
2872 	if (!(tp->t_modes.c_lflag & ECHO))
2873 		return (0);
2874 	i = 0;
2875 
2876 	/*
2877 	 * Echo control characters (c <= 37) only if the ECHOCTRL
2878 	 * flag is set as ^X.
2879 	 */
2880 
2881 	if ((tp->t_modes.c_lflag & ECHOCTL) &&
2882 	    (tp->t_modes.c_lflag & IEXTEN)) {
2883 		if (c <= 037 && c != '\t' && c != '\n') {
2884 			ldterm_outchar('^', q, ebsize, tp);
2885 			i++;
2886 			if (tp->t_modes.c_oflag & OLCUC)
2887 				c += 'a' - 1;
2888 			else
2889 				c += 'A' - 1;
2890 		} else if (c == 0177) {
2891 			ldterm_outchar('^', q, ebsize, tp);
2892 			i++;
2893 			c = '?';
2894 		}
2895 		ldterm_outchar(c, q, ebsize, tp);
2896 		return (i + 1);
2897 		/* echo only special control character and the Bell */
2898 	} else if ((c > 037 && c != 0177) || c == '\t' || c == '\n' ||
2899 	    c == '\r' || c == '\b' || c == 007 ||
2900 	    c == tp->t_modes.c_cc[VKILL]) {
2901 		ldterm_outchar(c, q, ebsize, tp);
2902 		return (i + 1);
2903 	}
2904 	return (i);
2905 }
2906 
2907 
2908 /*
2909  * Put a character on the output queue.
2910  */
2911 static void
ldterm_outchar(uchar_t c,queue_t * q,size_t bsize,ldtermstd_state_t * tp)2912 ldterm_outchar(uchar_t c, queue_t *q, size_t bsize, ldtermstd_state_t *tp)
2913 {
2914 	mblk_t *curbp;
2915 
2916 	/*
2917 	 * Don't even look at the characters unless we have something
2918 	 * useful to do with them.
2919 	 */
2920 	if ((tp->t_modes.c_oflag & OPOST) ||
2921 	    ((tp->t_modes.c_lflag & XCASE) &&
2922 	    (tp->t_modes.c_lflag & ICANON))) {
2923 		mblk_t *mp;
2924 
2925 		if ((mp = allocb(4, BPRI_HI)) == NULL) {
2926 			cmn_err(CE_WARN,
2927 			    "ldterm: (ldterm_outchar) out of blocks");
2928 			return;
2929 		}
2930 		*mp->b_wptr++ = c;
2931 		mp = ldterm_output_msg(q, mp, &tp->t_echomp, tp, bsize, 1);
2932 		if (mp != NULL)
2933 			freemsg(mp);
2934 
2935 	} else {
2936 		if ((curbp = tp->t_echomp) != NULL) {
2937 			while (curbp->b_cont != NULL)
2938 				curbp = curbp->b_cont;
2939 			if (curbp->b_datap->db_lim == curbp->b_wptr) {
2940 				mblk_t *newbp;
2941 
2942 				if ((newbp = allocb(bsize, BPRI_HI)) == NULL) {
2943 					cmn_err(CE_WARN,
2944 					    "ldterm_outchar: out of blocks");
2945 					return;
2946 				}
2947 				curbp->b_cont = newbp;
2948 				curbp = newbp;
2949 			}
2950 		} else {
2951 			if ((curbp = allocb(bsize, BPRI_HI)) == NULL) {
2952 				cmn_err(CE_WARN,
2953 				    "ldterm_outchar: out of blocks");
2954 				return;
2955 			}
2956 			tp->t_echomp = curbp;
2957 		}
2958 		*curbp->b_wptr++ = c;
2959 	}
2960 }
2961 
2962 
2963 /*
2964  * Copy a string, of length len, to the output queue.
2965  */
2966 static void
ldterm_outstring(uchar_t * cp,int len,queue_t * q,size_t bsize,ldtermstd_state_t * tp)2967 ldterm_outstring(uchar_t *cp, int len, queue_t *q, size_t bsize,
2968     ldtermstd_state_t *tp)
2969 {
2970 	while (len > 0) {
2971 		ldterm_outchar(*cp++, q, bsize, tp);
2972 		len--;
2973 	}
2974 }
2975 
2976 
2977 static mblk_t *
newmsg(ldtermstd_state_t * tp)2978 newmsg(ldtermstd_state_t *tp)
2979 {
2980 	mblk_t *bp;
2981 
2982 	/*
2983 	 * If no current message, allocate a block for it.
2984 	 */
2985 	if ((bp = tp->t_endmsg) == NULL) {
2986 		if ((bp = allocb(IBSIZE, BPRI_MED)) == NULL) {
2987 			cmn_err(CE_WARN,
2988 			    "ldterm: (ldtermrsrv/newmsg) out of blocks");
2989 			return (bp);
2990 		}
2991 		tp->t_message = bp;
2992 		tp->t_endmsg = bp;
2993 	}
2994 	return (bp);
2995 }
2996 
2997 
2998 static void
ldterm_msg_upstream(queue_t * q,ldtermstd_state_t * tp)2999 ldterm_msg_upstream(queue_t *q, ldtermstd_state_t *tp)
3000 {
3001 	ssize_t s;
3002 	mblk_t *bp;
3003 
3004 	bp = tp->t_message;
3005 	s = msgdsize(bp);
3006 	if (bp)
3007 		putnext(q, tp->t_message);
3008 
3009 	/*
3010 	 * update sysinfo canch character.
3011 	 */
3012 	if (CANON_MODE)
3013 		(void) drv_setparm(SYSCANC, s);
3014 	tp->t_message = NULL;
3015 	tp->t_endmsg = NULL;
3016 	tp->t_msglen = 0;
3017 	tp->t_rocount = 0;
3018 	tp->t_rd_request = 0;
3019 	if (tp->t_state & TS_MEUC) {
3020 		ASSERT(tp->t_eucp_mp);
3021 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
3022 		/* can't reset everything, as we may have other input */
3023 	}
3024 }
3025 
3026 
3027 /*
3028  * Re-enable the write-side service procedure.  When an allocation
3029  * failure causes write-side processing to stall, we disable the
3030  * write side and arrange to call this function when allocation once
3031  * again becomes possible.
3032  */
3033 static void
ldterm_wenable(void * addr)3034 ldterm_wenable(void *addr)
3035 {
3036 	queue_t *q = addr;
3037 	ldtermstd_state_t *tp;
3038 
3039 	tp = (ldtermstd_state_t *)q->q_ptr;
3040 	/*
3041 	 * The bufcall is no longer pending.
3042 	 */
3043 	tp->t_wbufcid = 0;
3044 	enableok(q);
3045 	qenable(q);
3046 }
3047 
3048 
3049 /*
3050  * Line discipline output queue put procedure.  Attempts to process
3051  * the message directly and send it on downstream, queueing it only
3052  * if there's already something pending or if its downstream neighbor
3053  * is clogged.
3054  */
3055 static int
ldtermwput(queue_t * q,mblk_t * mp)3056 ldtermwput(queue_t *q, mblk_t *mp)
3057 {
3058 	ldtermstd_state_t *tp;
3059 	unsigned char type = mp->b_datap->db_type;
3060 
3061 	tp = (ldtermstd_state_t *)q->q_ptr;
3062 
3063 	/*
3064 	 * Always process priority messages, regardless of whether or
3065 	 * not our queue is nonempty.
3066 	 */
3067 	if (type >= QPCTL) {
3068 		switch (type) {
3069 
3070 		case M_FLUSH:
3071 			/*
3072 			 * Get rid of it, see comment in
3073 			 * ldterm_dosig().
3074 			 */
3075 			if ((tp->t_state & TS_FLUSHWAIT) &&
3076 			    (*mp->b_rptr == FLUSHW)) {
3077 				tp->t_state &= ~TS_FLUSHWAIT;
3078 				freemsg(mp);
3079 				return (0);
3080 			}
3081 			/*
3082 			 * This is coming from above, so we only
3083 			 * handle the write queue here.  If FLUSHR is
3084 			 * set, it will get turned around at the
3085 			 * driver, and the read procedure will see it
3086 			 * eventually.
3087 			 */
3088 			if (*mp->b_rptr & FLUSHW) {
3089 				if ((tp->t_state & TS_ISPTSTTY) &&
3090 				    (*mp->b_rptr & FLUSHBAND))
3091 					flushband(q, *(mp->b_rptr + 1),
3092 					    FLUSHDATA);
3093 				else
3094 					flushq(q, FLUSHDATA);
3095 			}
3096 
3097 			putnext(q, mp);
3098 			/*
3099 			 * If a timed read is interrupted, there is
3100 			 * no way to cancel an existing M_READ
3101 			 * request.  We kludge by allowing a flush to
3102 			 * do so.
3103 			 */
3104 			if (tp->t_state & TS_MREAD)
3105 				vmin_satisfied(RD(q), tp, 0);
3106 			break;
3107 
3108 		case M_READ:
3109 			DEBUG1(("ldtermwmsg:M_READ RECEIVED\n"));
3110 			/*
3111 			 * Stream head needs data to satisfy timed
3112 			 * read. Has meaning only if ICANON flag is
3113 			 * off indicating raw mode
3114 			 */
3115 
3116 			DEBUG4((
3117 			    "M_READ: RAW_MODE=%d, CNT=%d, VMIN=%d, VTIME=%d\n",
3118 			    RAW_MODE, *(unsigned int *)mp->b_rptr, V_MIN,
3119 			    V_TIME));
3120 
3121 			tp->t_rd_request = *(unsigned int *)mp->b_rptr;
3122 
3123 			if (RAW_MODE) {
3124 				if (newmsg(tp) != NULL) {
3125 					/*
3126 					 * VMIN/VTIME processing...
3127 					 * The four possible cases are:
3128 					 *	MIN = 0, TIME > 0
3129 					 *	MIN = >, TIME = 0
3130 					 *	MIN > 0, TIME > 0
3131 					 *	MIN = 0, TIME = 0
3132 					 * These four conditions must be dealt
3133 					 * with on the read side as well in
3134 					 * ldterm_do_noncanon(). Set TS_MREAD
3135 					 * so that the read side will know
3136 					 * there is a pending read request
3137 					 * waiting at the stream head.  If we
3138 					 * can satisfy MIN do it here, rather
3139 					 * than on the read side.  If we can't,
3140 					 * start timers if necessary and let
3141 					 * the other side deal with it.
3142 					 *
3143 					 * We got another M_READ before the
3144 					 * pending one completed, cancel any
3145 					 * existing timeout.
3146 					 */
3147 					if (tp->t_state & TS_MREAD) {
3148 						vmin_satisfied(RD(q),
3149 						    tp, 0);
3150 					}
3151 					tp->t_state |= TS_MREAD;
3152 					/*
3153 					 * Case 1:  Any data will
3154 					 * satisfy read, otherwise
3155 					 * start timer
3156 					 */
3157 					if (V_MIN == 0 && V_TIME > 0) {
3158 						if (tp->t_msglen)
3159 							vmin_satisfied(RD(q),
3160 							    tp, 1);
3161 						else
3162 							vmin_settimer(RD(q));
3163 
3164 						/*
3165 						 * Case 2:  If we have enough
3166 						 * data, send up now.
3167 						 * Otherwise, the read side
3168 						 * should wait forever until MIN
3169 						 * is satisified.
3170 						 */
3171 					} else if (V_MIN > 0 && V_TIME == 0) {
3172 						if (tp->t_msglen >= (int)V_MIN)
3173 							vmin_satisfied(RD(q),
3174 							    tp, 1);
3175 
3176 						/*
3177 						 * Case 3:  If we can satisfy
3178 						 * the read, send it up. If we
3179 						 * don't have enough data, but
3180 						 * there is at least one char,
3181 						 * start a timer.  Otherwise,
3182 						 * let the read side start
3183 						 * the timer.
3184 						 */
3185 					} else if (V_MIN > 0 && V_TIME > 0) {
3186 						if (tp->t_msglen >= (int)V_MIN)
3187 							vmin_satisfied(RD(q),
3188 							    tp, 1);
3189 						else if (tp->t_msglen)
3190 							vmin_settimer(RD(q));
3191 						/*
3192 						 * Case 4:  Read returns
3193 						 * whatever data is available
3194 						 * or zero if none.
3195 						 */
3196 					} else { /* V_MIN == 0 && V_TIME == 0 */
3197 						vmin_satisfied(RD(q), tp, 1);
3198 					}
3199 
3200 				} else	/* should do bufcall, really! */
3201 					cmn_err(CE_WARN,
3202 					    "ldtermwmsg: out of blocks");
3203 			}
3204 			/*
3205 			 * pass M_READ down
3206 			 */
3207 			putnext(q, mp);
3208 			break;
3209 
3210 		default:
3211 			/* Pass it through unmolested. */
3212 			putnext(q, mp);
3213 			break;
3214 		}
3215 		return (0);
3216 	}
3217 	/*
3218 	 * If our queue is nonempty or there's a traffic jam
3219 	 * downstream, this message must get in line.
3220 	 */
3221 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
3222 		/*
3223 		 * Exception: ioctls, except for those defined to
3224 		 * take effect after output has drained, should be
3225 		 * processed immediately.
3226 		 */
3227 		if (type == M_IOCTL) {
3228 			struct iocblk *iocp;
3229 
3230 			iocp = (struct iocblk *)mp->b_rptr;
3231 			switch (iocp->ioc_cmd) {
3232 
3233 				/*
3234 				 * Queue these.
3235 				 */
3236 			case TCSETSW:
3237 			case TCSETSF:
3238 			case TCSETAW:
3239 			case TCSETAF:
3240 			case TCSBRK:
3241 				break;
3242 
3243 				/*
3244 				 * Handle all others immediately.
3245 				 */
3246 			default:
3247 				(void) ldtermwmsg(q, mp);
3248 				return (0);
3249 			}
3250 		}
3251 		(void) putq(q, mp);
3252 		return (0);
3253 	}
3254 	/*
3255 	 * We can take the fast path through, by simply calling
3256 	 * ldtermwmsg to dispose of mp.
3257 	 */
3258 	(void) ldtermwmsg(q, mp);
3259 	return (0);
3260 }
3261 
3262 
3263 /*
3264  * Line discipline output queue service procedure.
3265  */
3266 static int
ldtermwsrv(queue_t * q)3267 ldtermwsrv(queue_t *q)
3268 {
3269 	mblk_t *mp;
3270 
3271 	/*
3272 	 * We expect this loop to iterate at most once, but must be
3273 	 * prepared for more in case our upstream neighbor isn't
3274 	 * paying strict attention to what canput tells it.
3275 	 */
3276 	while ((mp = getq(q)) != NULL) {
3277 		/*
3278 		 * N.B.: ldtermwput has already handled high-priority
3279 		 * messages, so we don't have to worry about them
3280 		 * here. Hence, the putbq call is safe.
3281 		 */
3282 		if (!bcanputnext(q, mp->b_band)) {
3283 			(void) putbq(q, mp);
3284 			break;
3285 		}
3286 		if (!ldtermwmsg(q, mp)) {
3287 			/*
3288 			 * Couldn't handle the whole thing; give up
3289 			 * for now and wait to be rescheduled.
3290 			 */
3291 			break;
3292 		}
3293 	}
3294 	return (0);
3295 }
3296 
3297 
3298 /*
3299  * Process the write-side message denoted by mp.  If mp can't be
3300  * processed completely (due to allocation failures), put the
3301  * residual unprocessed part on the front of the write queue, disable
3302  * the queue, and schedule a qbufcall to arrange to complete its
3303  * processing later.
3304  *
3305  * Return 1 if the message was processed completely and 0 if not.
3306  *
3307  * This routine is called from both ldtermwput and ldtermwsrv to do the
3308  * actual work of dealing with mp.  ldtermwput will have already
3309  * dealt with high priority messages.
3310  */
3311 static int
ldtermwmsg(queue_t * q,mblk_t * mp)3312 ldtermwmsg(queue_t *q, mblk_t *mp)
3313 {
3314 	ldtermstd_state_t *tp;
3315 	mblk_t *residmp = NULL;
3316 	size_t size;
3317 
3318 	tp = (ldtermstd_state_t *)q->q_ptr;
3319 
3320 	switch (mp->b_datap->db_type) {
3321 
3322 	case M_IOCTL:
3323 		ldterm_do_ioctl(q, mp);
3324 		break;
3325 
3326 	case M_DATA:
3327 		{
3328 			mblk_t *omp = NULL;
3329 
3330 			if ((tp->t_modes.c_lflag & FLUSHO) &&
3331 			    (tp->t_modes.c_lflag & IEXTEN)) {
3332 				freemsg(mp);	/* drop on floor */
3333 				break;
3334 			}
3335 			tp->t_rocount = 0;
3336 			/*
3337 			 * Don't even look at the characters unless
3338 			 * we have something useful to do with them.
3339 			 */
3340 			if (((tp->t_modes.c_oflag & OPOST) ||
3341 			    ((tp->t_modes.c_lflag & XCASE) &&
3342 			    (tp->t_modes.c_lflag & ICANON))) &&
3343 			    (msgdsize(mp) || !(tp->t_state & TS_ISPTSTTY))) {
3344 				unsigned char band = mp->b_band;
3345 				short flag = mp->b_flag;
3346 
3347 				residmp = ldterm_output_msg(q, mp, &omp,
3348 				    tp, OBSIZE, 0);
3349 				if ((mp = omp) == NULL)
3350 					break;
3351 				mp->b_band |= band;
3352 				mp->b_flag |= flag;
3353 			}
3354 			/* Update sysinfo outch */
3355 			(void) drv_setparm(SYSOUTC, msgdsize(mp));
3356 			putnext(q, mp);
3357 			break;
3358 		}
3359 
3360 	default:
3361 		putnext(q, mp);	/* pass it through unmolested */
3362 		break;
3363 	}
3364 
3365 	if (residmp == NULL)
3366 		return (1);
3367 
3368 	/*
3369 	 * An allocation failure occurred that prevented the message
3370 	 * from being completely processed.  First, disable our
3371 	 * queue, since it's pointless to attempt further processing
3372 	 * until the allocation situation is resolved.  (This must
3373 	 * precede the putbq call below, which would otherwise mark
3374 	 * the queue to be serviced.)
3375 	 */
3376 	noenable(q);
3377 	/*
3378 	 * Stuff the remnant on our write queue so that we can
3379 	 * complete it later when times become less lean.  Note that
3380 	 * this sets QFULL, so that our upstream neighbor will be
3381 	 * blocked by flow control.
3382 	 */
3383 	(void) putbq(q, residmp);
3384 	/*
3385 	 * Schedule a qbufcall to re-enable the queue.  The failure
3386 	 * won't have been for an allocation of more than OBSIZE
3387 	 * bytes, so don't ask for more than that from bufcall.
3388 	 */
3389 	size = msgdsize(residmp);
3390 	if (size > OBSIZE)
3391 		size = OBSIZE;
3392 	if (tp->t_wbufcid)
3393 		qunbufcall(q, tp->t_wbufcid);
3394 	tp->t_wbufcid = qbufcall(q, size, BPRI_MED, ldterm_wenable, q);
3395 
3396 	return (0);
3397 }
3398 
3399 
3400 /*
3401  * Perform output processing on a message, accumulating the output
3402  * characters in a new message.
3403  */
3404 static mblk_t *
ldterm_output_msg(queue_t * q,mblk_t * imp,mblk_t ** omp,ldtermstd_state_t * tp,size_t bsize,int echoing)3405 ldterm_output_msg(queue_t *q, mblk_t *imp, mblk_t **omp,
3406     ldtermstd_state_t *tp, size_t bsize, int echoing)
3407 {
3408 	mblk_t *ibp;		/* block we're examining from input message */
3409 	mblk_t *obp;		/* block we're filling in output message */
3410 	mblk_t *cbp;		/* continuation block */
3411 	mblk_t *oobp;		/* old value of obp; valid if NEW_BLOCK fails */
3412 	mblk_t **contpp;	/* where to stuff ptr to newly-allocated blk */
3413 	unsigned char c, n;
3414 	int count, ctype;
3415 	ssize_t bytes_left;
3416 
3417 	mblk_t *bp;		/* block to stuff an M_DELAY message in */
3418 
3419 
3420 	/*
3421 	 * Allocate a new block into which to put bytes. If we can't,
3422 	 * we just drop the rest of the message on the floor. If x is
3423 	 * non-zero, just fall thru; failure requires cleanup before
3424 	 * going out
3425 	 */
3426 
3427 #define	NEW_BLOCK(x) \
3428 	{ \
3429 		oobp = obp; \
3430 		if ((obp = allocb(bsize, BPRI_MED)) == NULL) { \
3431 			if (x == 0) \
3432 				goto outofbufs; \
3433 		} else { \
3434 			*contpp = obp; \
3435 			contpp = &obp->b_cont; \
3436 			bytes_left = obp->b_datap->db_lim - obp->b_wptr; \
3437 		} \
3438 	}
3439 
3440 	ibp = imp;
3441 
3442 	/*
3443 	 * When we allocate the first block of a message, we should
3444 	 * stuff the pointer to it in "*omp".  All subsequent blocks
3445 	 * should have the pointer to them stuffed into the "b_cont"
3446 	 * field of the previous block.  "contpp" points to the place
3447 	 * where we should stuff the pointer.
3448 	 *
3449 	 * If we already have a message we're filling in, continue doing
3450 	 * so.
3451 	 */
3452 	if ((obp = *omp) != NULL) {
3453 		while (obp->b_cont != NULL)
3454 			obp = obp->b_cont;
3455 		contpp = &obp->b_cont;
3456 		bytes_left = obp->b_datap->db_lim - obp->b_wptr;
3457 	} else {
3458 		contpp = omp;
3459 		bytes_left = 0;
3460 	}
3461 
3462 	do {
3463 		while (ibp->b_rptr < ibp->b_wptr) {
3464 			/*
3465 			 * Make sure there's room for one more
3466 			 * character.  At most, we'll need "t_maxeuc"
3467 			 * bytes.
3468 			 */
3469 			if ((bytes_left < (int)tp->t_maxeuc)) {
3470 				/* LINTED */
3471 				NEW_BLOCK(0);
3472 			}
3473 			/*
3474 			 * If doing XCASE processing (not very
3475 			 * likely, in this day and age), look at each
3476 			 * character individually.
3477 			 */
3478 			if ((tp->t_modes.c_lflag & XCASE) &&
3479 			    (tp->t_modes.c_lflag & ICANON)) {
3480 				c = *ibp->b_rptr++;
3481 
3482 				/*
3483 				 * We need to make sure that this is not
3484 				 * a following byte of a multibyte character
3485 				 * before applying an XCASE processing.
3486 				 *
3487 				 * tp->t_eucign will be 0 if and only
3488 				 * if the current 'c' is an ASCII character
3489 				 * and also a byte. Otherwise, it will have
3490 				 * the byte length of a multibyte character.
3491 				 */
3492 				if ((tp->t_state & TS_MEUC) &&
3493 				    tp->t_eucign == 0 && NOTASCII(c)) {
3494 					tp->t_eucign =
3495 					    tp->t_csmethods.ldterm_memwidth(
3496 					    c, (void *)tp);
3497 					tp->t_scratch_len = tp->t_eucign;
3498 
3499 					if (tp->t_csdata.codeset_type !=
3500 					    LDTERM_CS_TYPE_UTF8) {
3501 						tp->t_col +=
3502 						    tp->
3503 						    t_csmethods.
3504 						    ldterm_dispwidth(c,
3505 						    (void *)tp,
3506 						    tp->t_modes.c_lflag &
3507 						    ECHOCTL);
3508 					}
3509 				}
3510 
3511 				/*
3512 				 * If character is mapped on output,
3513 				 * put out a backslash followed by
3514 				 * what it is mapped to.
3515 				 */
3516 				if (tp->t_eucign == 0 && omaptab[c] != 0 &&
3517 				    (!echoing || c != '\\')) {
3518 					/* backslash is an ordinary character */
3519 					tp->t_col++;
3520 					*obp->b_wptr++ = '\\';
3521 					bytes_left--;
3522 					if (bytes_left == 0) {
3523 						/* LINTED */
3524 						NEW_BLOCK(1);
3525 					}
3526 					/*
3527 					 * Allocation failed, make
3528 					 * state consistent before
3529 					 * returning
3530 					 */
3531 					if (obp == NULL) {
3532 						ibp->b_rptr--;
3533 						tp->t_col--;
3534 						oobp->b_wptr--;
3535 						goto outofbufs;
3536 					}
3537 					c = omaptab[c];
3538 				}
3539 				/*
3540 				 * If no other output processing is
3541 				 * required, push the character into
3542 				 * the block and get another.
3543 				 */
3544 				if (!(tp->t_modes.c_oflag & OPOST)) {
3545 					if (tp->t_eucign > 0) {
3546 						--tp->t_eucign;
3547 					} else {
3548 						tp->t_col++;
3549 					}
3550 					*obp->b_wptr++ = c;
3551 					bytes_left--;
3552 					continue;
3553 				}
3554 				/*
3555 				 * OPOST output flag is set. Map
3556 				 * lower case to upper case if OLCUC
3557 				 * flag is set and the 'c' is a lowercase
3558 				 * ASCII character.
3559 				 */
3560 				if (tp->t_eucign == 0 &&
3561 				    (tp->t_modes.c_oflag & OLCUC) &&
3562 				    c >= 'a' && c <= 'z')
3563 					c -= 'a' - 'A';
3564 			} else {
3565 				/*
3566 				 * Copy all the ORDINARY characters,
3567 				 * possibly mapping upper case to
3568 				 * lower case.  We use "movtuc",
3569 				 * STOPPING when we can't move some
3570 				 * character. For multi-byte or
3571 				 * multi-column EUC, we can't depend
3572 				 * on the regular tables. Rather than
3573 				 * just drop through to the "big
3574 				 * switch" for all characters, it
3575 				 * _might_ be faster to let "movtuc"
3576 				 * move a bunch of characters.
3577 				 * Chances are, even in multi-byte
3578 				 * mode we'll have lots of ASCII
3579 				 * going through. We check the flag
3580 				 * once, and call movtuc with the
3581 				 * appropriate table as an argument.
3582 				 *
3583 				 * "movtuc will work for all codeset
3584 				 * types since it stops at the beginning
3585 				 * byte of a multibyte character.
3586 				 */
3587 				size_t bytes_to_move;
3588 				size_t bytes_moved;
3589 
3590 				ASSERT(ibp->b_wptr >= ibp->b_rptr);
3591 				bytes_to_move = ibp->b_wptr - ibp->b_rptr;
3592 				if (bytes_to_move > bytes_left)
3593 					bytes_to_move = bytes_left;
3594 				if (tp->t_state & TS_MEUC) {
3595 					bytes_moved = movtuc(bytes_to_move,
3596 					    ibp->b_rptr, obp->b_wptr,
3597 					    (tp->t_modes.c_oflag & OLCUC ?
3598 					    elcuctab : enotrantab));
3599 				} else {
3600 					bytes_moved = movtuc(bytes_to_move,
3601 					    ibp->b_rptr, obp->b_wptr,
3602 					    (tp->t_modes.c_oflag & OLCUC ?
3603 					    lcuctab : notrantab));
3604 				}
3605 				/*
3606 				 * We're save to just do this column
3607 				 * calculation, because if TS_MEUC is
3608 				 * set, we used the proper EUC
3609 				 * tables, and won't have copied any
3610 				 * EUC bytes.
3611 				 */
3612 				tp->t_col += bytes_moved;
3613 				ibp->b_rptr += bytes_moved;
3614 				obp->b_wptr += bytes_moved;
3615 				bytes_left -= bytes_moved;
3616 				if (ibp->b_rptr >= ibp->b_wptr)
3617 					continue;	/* moved all of block */
3618 				if (bytes_left == 0) {
3619 					/* LINTED */
3620 					NEW_BLOCK(0);
3621 				}
3622 				c = *ibp->b_rptr++;	/* stopper */
3623 			}
3624 
3625 			/*
3626 			 * Again, we need to make sure that this is not
3627 			 * a following byte of a multibyte character at
3628 			 * here.
3629 			 *
3630 			 * 'tp->t_eucign' will be 0 iff the current 'c' is
3631 			 * an ASCII character. Otherwise, it will have
3632 			 * the byte length of a multibyte character.
3633 			 * We also add the display width to 'tp->t_col' if
3634 			 * the current codeset is not UTF-8 since this is
3635 			 * a leading byte of a multibyte character.
3636 			 * For UTF-8 codeset type, we add the display width
3637 			 * when we get the last byte of a character.
3638 			 */
3639 			if ((tp->t_state & TS_MEUC) && tp->t_eucign == 0 &&
3640 			    NOTASCII(c)) {
3641 				tp->t_eucign = tp->t_csmethods.ldterm_memwidth(
3642 				    c, (void *)tp);
3643 				tp->t_scratch_len = tp->t_eucign;
3644 
3645 				if (tp->t_csdata.codeset_type !=
3646 				    LDTERM_CS_TYPE_UTF8) {
3647 					tp->t_col +=
3648 					    tp->t_csmethods.ldterm_dispwidth(c,
3649 					    (void *)tp,
3650 					    tp->t_modes.c_lflag & ECHOCTL);
3651 				}
3652 			}
3653 
3654 			/*
3655 			 * If the driver has requested, don't process
3656 			 * output flags.  However, if we're in
3657 			 * multi-byte mode, we HAVE to look at
3658 			 * EVERYTHING going out to maintain column
3659 			 * position properly. Therefore IF the driver
3660 			 * says don't AND we're not doing multi-byte,
3661 			 * then don't do it.  Otherwise, do it.
3662 			 *
3663 			 * NOTE:  Hardware USUALLY doesn't expand tabs
3664 			 * properly for multi-byte situations anyway;
3665 			 * that's a known problem with the 3B2
3666 			 * "PORTS" board firmware, and any other
3667 			 * hardware that doesn't ACTUALLY know about
3668 			 * the current EUC mapping that WE are using
3669 			 * at this very moment.  The problem is that
3670 			 * memory width is INDEPENDENT of screen
3671 			 * width - no relation - so WE know how wide
3672 			 * the characters are, but an off-the-host
3673 			 * board probably doesn't.  So, until we're
3674 			 * SURE that the hardware below us can
3675 			 * correctly expand tabs in a
3676 			 * multi-byte/multi-column EUC situation, we
3677 			 * do it ourselves.
3678 			 */
3679 			/*
3680 			 * Map <CR>to<NL> on output if OCRNL flag
3681 			 * set. ONLCR processing is not done if OCRNL
3682 			 * is set.
3683 			 */
3684 			if (c == '\r' && (tp->t_modes.c_oflag & OCRNL)) {
3685 				c = '\n';
3686 				ctype = typetab[c];
3687 				goto jocrnl;
3688 			}
3689 
3690 			if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_EUC) {
3691 				ctype = typetab[c];
3692 			} else {
3693 				/*
3694 				 * In other codeset types, we safely assume
3695 				 * any byte of a multibyte character will have
3696 				 * 'ORDINARY' type. For ASCII characters, we
3697 				 * still use the typetab[].
3698 				 */
3699 				if (tp->t_eucign == 0)
3700 					ctype = typetab[c];
3701 				else
3702 					ctype = ORDINARY;
3703 			}
3704 
3705 			/*
3706 			 * Map <NL> to <CR><NL> on output if ONLCR
3707 			 * flag is set.
3708 			 */
3709 			if (c == '\n' && (tp->t_modes.c_oflag & ONLCR)) {
3710 				if (!(tp->t_state & TS_TTCR)) {
3711 					tp->t_state |= TS_TTCR;
3712 					c = '\r';
3713 					ctype = typetab['\r'];
3714 					--ibp->b_rptr;
3715 				} else
3716 					tp->t_state &= ~TS_TTCR;
3717 			}
3718 			/*
3719 			 * Delay values and column position
3720 			 * calculated here.  For EUC chars in
3721 			 * multi-byte mode, we use "t_eucign" to help
3722 			 * calculate columns.  When we see the first
3723 			 * byte of an EUC, we set t_eucign to the
3724 			 * number of bytes that will FOLLOW it, and
3725 			 * we add the screen width of the WHOLE EUC
3726 			 * character to the column position.  In
3727 			 * particular, we can't count SS2 or SS3 as
3728 			 * printing characters.  Remember, folks, the
3729 			 * screen width and memory width are
3730 			 * independent - no relation. We could have
3731 			 * dropped through for ASCII, but we want to
3732 			 * catch any bad characters (i.e., t_eucign
3733 			 * set and an ASCII char received) and
3734 			 * possibly report the garbage situation.
3735 			 */
3736 	jocrnl:
3737 
3738 			count = 0;
3739 			switch (ctype) {
3740 
3741 			case T_SS2:
3742 			case T_SS3:
3743 			case ORDINARY:
3744 				if (tp->t_state & TS_MEUC) {
3745 					if (tp->t_eucign) {
3746 						*obp->b_wptr++ = c;
3747 						bytes_left--;
3748 
3749 						tp->t_scratch[tp->t_scratch_len
3750 						    - tp->t_eucign] = c;
3751 
3752 						--tp->t_eucign;
3753 
3754 						if (tp->t_csdata.codeset_type
3755 						    == LDTERM_CS_TYPE_UTF8 &&
3756 						    tp->t_eucign <= 0) {
3757 							tp->t_col +=
3758 							    ldterm_utf8_width(
3759 							    tp->t_scratch,
3760 							    tp->t_scratch_len);
3761 						}
3762 					} else {
3763 						if (tp->t_modes.c_oflag & OLCUC)
3764 							n = elcuctab[c];
3765 						else
3766 							n = enotrantab[c];
3767 						if (n)
3768 							c = n;
3769 						tp->t_col++;
3770 						*obp->b_wptr++ = c;
3771 						bytes_left--;
3772 					}
3773 				} else {	/* ho hum, ASCII mode... */
3774 					if (tp->t_modes.c_oflag & OLCUC)
3775 						n = lcuctab[c];
3776 					else
3777 						n = notrantab[c];
3778 					if (n)
3779 						c = n;
3780 					tp->t_col++;
3781 					*obp->b_wptr++ = c;
3782 					bytes_left--;
3783 				}
3784 				break;
3785 
3786 				/*
3787 				 * If we're doing ECHOCTL, we've
3788 				 * already mapped the thing during
3789 				 * the process of canonising.  Don't
3790 				 * bother here, as it's not one that
3791 				 * we did.
3792 				 */
3793 			case CONTROL:
3794 				*obp->b_wptr++ = c;
3795 				bytes_left--;
3796 				break;
3797 
3798 				/*
3799 				 * This is probably a backspace
3800 				 * received, not one that we're
3801 				 * echoing.  Let it go as a
3802 				 * single-column backspace.
3803 				 */
3804 			case BACKSPACE:
3805 				if (tp->t_col)
3806 					tp->t_col--;
3807 				if (tp->t_modes.c_oflag & BSDLY) {
3808 					if (tp->t_modes.c_oflag & OFILL)
3809 						count = 1;
3810 				}
3811 				*obp->b_wptr++ = c;
3812 				bytes_left--;
3813 				break;
3814 
3815 			case NEWLINE:
3816 				if (tp->t_modes.c_oflag & ONLRET)
3817 					goto cr;
3818 				if ((tp->t_modes.c_oflag & NLDLY) == NL1)
3819 					count = 2;
3820 				*obp->b_wptr++ = c;
3821 				bytes_left--;
3822 				break;
3823 
3824 			case TAB:
3825 				/*
3826 				 * Map '\t' to spaces if XTABS flag
3827 				 * is set.  The calculation of
3828 				 * "t_eucign" has probably insured
3829 				 * that column will be correct, as we
3830 				 * bumped t_col by the DISP width,
3831 				 * not the memory width.
3832 				 */
3833 				if ((tp->t_modes.c_oflag & TABDLY) == XTABS) {
3834 					for (;;) {
3835 						*obp->b_wptr++ = ' ';
3836 						bytes_left--;
3837 						tp->t_col++;
3838 						if ((tp->t_col & 07) == 0)
3839 							break;	/* every 8th */
3840 						/*
3841 						 * If we don't have
3842 						 * room to fully
3843 						 * expand this tab in
3844 						 * this block, back
3845 						 * up to continue
3846 						 * expanding it into
3847 						 * the next block.
3848 						 */
3849 						if (obp->b_wptr >=
3850 						    obp->b_datap->db_lim) {
3851 							ibp->b_rptr--;
3852 							break;
3853 						}
3854 					}
3855 				} else {
3856 					tp->t_col |= 07;
3857 					tp->t_col++;
3858 					if (tp->t_modes.c_oflag & OFILL) {
3859 						if (tp->t_modes.c_oflag &
3860 						    TABDLY)
3861 							count = 2;
3862 					} else {
3863 						switch (tp->t_modes.c_oflag &
3864 						    TABDLY) {
3865 						case TAB2:
3866 							count = 6;
3867 							break;
3868 
3869 						case TAB1:
3870 							count = 1 + (tp->t_col |
3871 							    ~07);
3872 							if (count < 5)
3873 								count = 0;
3874 							break;
3875 						}
3876 					}
3877 					*obp->b_wptr++ = c;
3878 					bytes_left--;
3879 				}
3880 				break;
3881 
3882 			case VTAB:
3883 				if ((tp->t_modes.c_oflag & VTDLY) &&
3884 				    !(tp->t_modes.c_oflag & OFILL))
3885 					count = 127;
3886 				*obp->b_wptr++ = c;
3887 				bytes_left--;
3888 				break;
3889 
3890 			case RETURN:
3891 				/*
3892 				 * Ignore <CR> in column 0 if ONOCR
3893 				 * flag set.
3894 				 */
3895 				if (tp->t_col == 0 &&
3896 				    (tp->t_modes.c_oflag & ONOCR))
3897 					break;
3898 
3899 		cr:
3900 				switch (tp->t_modes.c_oflag & CRDLY) {
3901 
3902 				case CR1:
3903 					if (tp->t_modes.c_oflag & OFILL)
3904 						count = 2;
3905 					else
3906 						count = tp->t_col % 2;
3907 					break;
3908 
3909 				case CR2:
3910 					if (tp->t_modes.c_oflag & OFILL)
3911 						count = 4;
3912 					else
3913 						count = 6;
3914 					break;
3915 
3916 				case CR3:
3917 					if (tp->t_modes.c_oflag & OFILL)
3918 						count = 0;
3919 					else
3920 						count = 9;
3921 					break;
3922 				}
3923 				tp->t_col = 0;
3924 				*obp->b_wptr++ = c;
3925 				bytes_left--;
3926 				break;
3927 			}
3928 
3929 			if (count != 0) {
3930 				if (tp->t_modes.c_oflag & OFILL) {
3931 					do {
3932 						if (bytes_left == 0) {
3933 							/* LINTED */
3934 							NEW_BLOCK(0);
3935 						}
3936 						if (tp->t_modes.c_oflag & OFDEL)
3937 							*obp->b_wptr++ = CDEL;
3938 						else
3939 							*obp->b_wptr++ = CNUL;
3940 						bytes_left--;
3941 					} while (--count != 0);
3942 				} else {
3943 					if ((tp->t_modes.c_lflag & FLUSHO) &&
3944 					    (tp->t_modes.c_lflag & IEXTEN)) {
3945 						/* drop on floor */
3946 						freemsg(*omp);
3947 					} else {
3948 						/*
3949 						 * Update sysinfo
3950 						 * outch
3951 						 */
3952 						(void) drv_setparm(SYSOUTC,
3953 						    msgdsize(*omp));
3954 						putnext(q, *omp);
3955 						/*
3956 						 * Send M_DELAY
3957 						 * downstream
3958 						 */
3959 						if ((bp =
3960 						    allocb(1, BPRI_MED)) !=
3961 						    NULL) {
3962 							bp->b_datap->db_type =
3963 							    M_DELAY;
3964 							*bp->b_wptr++ =
3965 							    (uchar_t)count;
3966 							putnext(q, bp);
3967 						}
3968 					}
3969 					bytes_left = 0;
3970 					/*
3971 					 * We have to start a new
3972 					 * message; the delay
3973 					 * introduces a break between
3974 					 * messages.
3975 					 */
3976 					*omp = NULL;
3977 					contpp = omp;
3978 				}
3979 			}
3980 		}
3981 		cbp = ibp->b_cont;
3982 		freeb(ibp);
3983 	} while ((ibp = cbp) != NULL);	/* next block, if any */
3984 
3985 outofbufs:
3986 	return (ibp);
3987 #undef NEW_BLOCK
3988 }
3989 
3990 
3991 #if !defined(__sparc)
3992 int
movtuc(size_t size,unsigned char * from,unsigned char * origto,unsigned char * table)3993 movtuc(size_t size, unsigned char *from, unsigned char *origto,
3994     unsigned char *table)
3995 {
3996 	unsigned char *to = origto;
3997 	unsigned char c;
3998 
3999 	while (size != 0 && (c = table[*from++]) != 0) {
4000 		*to++ = c;
4001 		size--;
4002 	}
4003 	return (to - origto);
4004 }
4005 #endif
4006 
4007 static void
ldterm_flush_output(uchar_t c,queue_t * q,ldtermstd_state_t * tp)4008 ldterm_flush_output(uchar_t c, queue_t *q, ldtermstd_state_t *tp)
4009 {
4010 	/* Already conditioned with IEXTEN during VDISCARD processing */
4011 	if (tp->t_modes.c_lflag & FLUSHO)
4012 		tp->t_modes.c_lflag &= ~FLUSHO;
4013 	else {
4014 		flushq(q, FLUSHDATA);	/* flush our write queue */
4015 		/* flush ones below us */
4016 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
4017 		if ((tp->t_echomp = allocb(EBSIZE, BPRI_HI)) != NULL) {
4018 			(void) ldterm_echo(c, q, 1, tp);
4019 			if (tp->t_msglen != 0)
4020 				ldterm_reprint(q, EBSIZE, tp);
4021 			if (tp->t_echomp != NULL) {
4022 				putnext(q, tp->t_echomp);
4023 				tp->t_echomp = NULL;
4024 			}
4025 		}
4026 		tp->t_modes.c_lflag |= FLUSHO;
4027 	}
4028 }
4029 
4030 
4031 /*
4032  * Signal generated by the reader: M_PCSIG and M_FLUSH messages sent.
4033  */
4034 static void
ldterm_dosig(queue_t * q,int sig,uchar_t c,int mtype,int mode)4035 ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode)
4036 {
4037 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
4038 	int sndsig = 0;
4039 
4040 	/*
4041 	 * c == \0 is brk case; need to flush on BRKINT even if
4042 	 * noflsh is set.
4043 	 */
4044 	if ((!(tp->t_modes.c_lflag & NOFLSH)) || (c == '\0')) {
4045 		if (mode) {
4046 			if (tp->t_state & TS_TTSTOP) {
4047 				sndsig = 1;
4048 				(void) putnextctl1(q, mtype, sig);
4049 			}
4050 			/*
4051 			 * Flush read or write side.
4052 			 * Restart the input or output.
4053 			 */
4054 			if (mode & FLUSHR) {
4055 				flushq(q, FLUSHDATA);
4056 				(void) putnextctl1(WR(q), M_FLUSH, mode);
4057 				if (tp->t_state & (TS_TBLOCK|TS_IFBLOCK)) {
4058 					(void) putnextctl(WR(q), M_STARTI);
4059 					tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
4060 				}
4061 			}
4062 			if (mode & FLUSHW) {
4063 				flushq(WR(q), FLUSHDATA);
4064 				/*
4065 				 * XXX This is extremely gross.
4066 				 * Since we can't be sure our M_FLUSH
4067 				 * will have run its course by the
4068 				 * time we do the echo below, we set
4069 				 * state and toss it in the write put
4070 				 * routine to prevent flushing our
4071 				 * own data.  Note that downstream
4072 				 * modules on the write side will be
4073 				 * flushed by the M_FLUSH sent above.
4074 				 */
4075 				tp->t_state |= TS_FLUSHWAIT;
4076 				(void) putnextctl1(q, M_FLUSH, FLUSHW);
4077 				if (tp->t_state & TS_TTSTOP) {
4078 					(void) putnextctl(WR(q), M_START);
4079 					tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
4080 				}
4081 			}
4082 		}
4083 	}
4084 	tp->t_state &= ~TS_QUOT;
4085 	if (sndsig == 0)
4086 		(void) putnextctl1(q, mtype, sig);
4087 
4088 	if (c != '\0') {
4089 		if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) {
4090 			if (ldterm_echo(c, WR(q), 4, tp) > 0 ||
4091 			    (tp->t_state & TS_ISPTSTTY))
4092 				putnext(WR(q), tp->t_echomp);
4093 			else
4094 				freemsg(tp->t_echomp);
4095 			tp->t_echomp = NULL;
4096 		}
4097 	}
4098 }
4099 
4100 
4101 /*
4102  * Called when an M_IOCTL message is seen on the write queue; does
4103  * whatever we're supposed to do with it, and either replies
4104  * immediately or passes it to the next module down.
4105  */
4106 static void
ldterm_do_ioctl(queue_t * q,mblk_t * mp)4107 ldterm_do_ioctl(queue_t *q, mblk_t *mp)
4108 {
4109 	ldtermstd_state_t *tp;
4110 	struct iocblk *iocp;
4111 	struct eucioc *euciocp;	/* needed for EUC ioctls */
4112 	ldterm_cs_data_user_t *csdp;
4113 	int i;
4114 	int locale_name_sz;
4115 	uchar_t maxbytelen;
4116 	uchar_t maxscreenlen;
4117 	int error;
4118 
4119 	iocp = (struct iocblk *)mp->b_rptr;
4120 	tp = (ldtermstd_state_t *)q->q_ptr;
4121 
4122 	switch (iocp->ioc_cmd) {
4123 
4124 	case TCSETS:
4125 	case TCSETSW:
4126 	case TCSETSF:
4127 		{
4128 			/*
4129 			 * Set current parameters and special
4130 			 * characters.
4131 			 */
4132 			struct termios *cb;
4133 			struct termios oldmodes;
4134 
4135 			error = miocpullup(mp, sizeof (struct termios));
4136 			if (error != 0) {
4137 				miocnak(q, mp, 0, error);
4138 				return;
4139 			}
4140 
4141 			cb = (struct termios *)mp->b_cont->b_rptr;
4142 
4143 			oldmodes = tp->t_amodes;
4144 			tp->t_amodes = *cb;
4145 			if ((tp->t_amodes.c_lflag & PENDIN) &&
4146 			    (tp->t_modes.c_lflag & IEXTEN)) {
4147 				/*
4148 				 * Yuk.  The C shell file completion
4149 				 * code actually uses this "feature",
4150 				 * so we have to support it.
4151 				 */
4152 				if (tp->t_message != NULL) {
4153 					tp->t_state |= TS_RESCAN;
4154 					qenable(RD(q));
4155 				}
4156 				tp->t_amodes.c_lflag &= ~PENDIN;
4157 			}
4158 			bcopy(tp->t_amodes.c_cc, tp->t_modes.c_cc, NCCS);
4159 
4160 			/*
4161 			 * ldterm_adjust_modes does not deal with
4162 			 * cflags
4163 			 */
4164 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
4165 
4166 			ldterm_adjust_modes(tp);
4167 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
4168 				miocnak(q, mp, 0, EAGAIN);
4169 				return;
4170 			}
4171 			/*
4172 			 * The driver may want to know about the
4173 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
4174 			 * PARMRK, INPCK, IXON, IXANY.
4175 			 */
4176 			break;
4177 		}
4178 
4179 	case TCSETA:
4180 	case TCSETAW:
4181 	case TCSETAF:
4182 		{
4183 			/*
4184 			 * Old-style "ioctl" to set current
4185 			 * parameters and special characters. Don't
4186 			 * clear out the unset portions, leave them
4187 			 * as they are.
4188 			 */
4189 			struct termio *cb;
4190 			struct termios oldmodes;
4191 
4192 			error = miocpullup(mp, sizeof (struct termio));
4193 			if (error != 0) {
4194 				miocnak(q, mp, 0, error);
4195 				return;
4196 			}
4197 
4198 			cb = (struct termio *)mp->b_cont->b_rptr;
4199 
4200 			oldmodes = tp->t_amodes;
4201 			tp->t_amodes.c_iflag =
4202 			    (tp->t_amodes.c_iflag & 0xffff0000 | cb->c_iflag);
4203 			tp->t_amodes.c_oflag =
4204 			    (tp->t_amodes.c_oflag & 0xffff0000 | cb->c_oflag);
4205 			tp->t_amodes.c_cflag =
4206 			    (tp->t_amodes.c_cflag & 0xffff0000 | cb->c_cflag);
4207 			tp->t_amodes.c_lflag =
4208 			    (tp->t_amodes.c_lflag & 0xffff0000 | cb->c_lflag);
4209 
4210 			bcopy(cb->c_cc, tp->t_modes.c_cc, NCC);
4211 			/* TCGETS returns amodes, so update that too */
4212 			bcopy(cb->c_cc, tp->t_amodes.c_cc, NCC);
4213 
4214 			/* ldterm_adjust_modes does not deal with cflags */
4215 
4216 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
4217 
4218 			ldterm_adjust_modes(tp);
4219 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
4220 				miocnak(q, mp, 0, EAGAIN);
4221 				return;
4222 			}
4223 			/*
4224 			 * The driver may want to know about the
4225 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
4226 			 * PARMRK, INPCK, IXON, IXANY.
4227 			 */
4228 			break;
4229 		}
4230 
4231 	case TCFLSH:
4232 		/*
4233 		 * Do the flush on the write queue immediately, and
4234 		 * queue up any flush on the read queue for the
4235 		 * service procedure to see.  Then turn it into the
4236 		 * appropriate M_FLUSH message, so that the module
4237 		 * below us doesn't have to know about TCFLSH.
4238 		 */
4239 		error = miocpullup(mp, sizeof (int));
4240 		if (error != 0) {
4241 			miocnak(q, mp, 0, error);
4242 			return;
4243 		}
4244 
4245 		ASSERT(mp->b_datap != NULL);
4246 		if (*(int *)mp->b_cont->b_rptr == 0) {
4247 			ASSERT(mp->b_datap != NULL);
4248 			(void) putnextctl1(q, M_FLUSH, FLUSHR);
4249 			(void) putctl1(RD(q), M_FLUSH, FLUSHR);
4250 		} else if (*(int *)mp->b_cont->b_rptr == 1) {
4251 			flushq(q, FLUSHDATA);
4252 			ASSERT(mp->b_datap != NULL);
4253 			tp->t_state |= TS_FLUSHWAIT;
4254 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHW);
4255 			(void) putnextctl1(q, M_FLUSH, FLUSHW);
4256 		} else if (*(int *)mp->b_cont->b_rptr == 2) {
4257 			flushq(q, FLUSHDATA);
4258 			ASSERT(mp->b_datap != NULL);
4259 			(void) putnextctl1(q, M_FLUSH, FLUSHRW);
4260 			tp->t_state |= TS_FLUSHWAIT;
4261 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHRW);
4262 		} else {
4263 			miocnak(q, mp, 0, EINVAL);
4264 			return;
4265 		}
4266 		ASSERT(mp->b_datap != NULL);
4267 		iocp->ioc_rval = 0;
4268 		miocack(q, mp, 0, 0);
4269 		return;
4270 
4271 	case TCXONC:
4272 		error = miocpullup(mp, sizeof (int));
4273 		if (error != 0) {
4274 			miocnak(q, mp, 0, error);
4275 			return;
4276 		}
4277 
4278 		switch (*(int *)mp->b_cont->b_rptr) {
4279 		case 0:
4280 			if (!(tp->t_state & TS_TTSTOP)) {
4281 				(void) putnextctl(q, M_STOP);
4282 				tp->t_state |= (TS_TTSTOP|TS_OFBLOCK);
4283 			}
4284 			break;
4285 
4286 		case 1:
4287 			if (tp->t_state & TS_TTSTOP) {
4288 				(void) putnextctl(q, M_START);
4289 				tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
4290 			}
4291 			break;
4292 
4293 		case 2:
4294 			(void) putnextctl(q, M_STOPI);
4295 			tp->t_state |= (TS_TBLOCK|TS_IFBLOCK);
4296 			break;
4297 
4298 		case 3:
4299 			(void) putnextctl(q, M_STARTI);
4300 			tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
4301 			break;
4302 
4303 		default:
4304 			miocnak(q, mp, 0, EINVAL);
4305 			return;
4306 		}
4307 		ASSERT(mp->b_datap != NULL);
4308 		iocp->ioc_rval = 0;
4309 		miocack(q, mp, 0, 0);
4310 		return;
4311 		/*
4312 		 * TCSBRK is expected to be handled by the driver.
4313 		 * The reason its left for the driver is that when
4314 		 * the argument to TCSBRK is zero driver has to drain
4315 		 * the data and sending a M_IOCACK from LDTERM before
4316 		 * the driver drains the data is going to cause
4317 		 * problems.
4318 		 */
4319 
4320 		/*
4321 		 * The following are EUC related ioctls.  For
4322 		 * EUC_WSET, we have to pass the information on, even
4323 		 * though we ACK the call.  It's vital in the EUC
4324 		 * environment that everybody downstream knows about
4325 		 * the EUC codeset widths currently in use; we
4326 		 * therefore pass down the information in an M_CTL
4327 		 * message.  It will bottom out in the driver.
4328 		 */
4329 	case EUC_WSET:
4330 		{
4331 
4332 			/* only needed for EUC_WSET */
4333 			struct iocblk *riocp;
4334 
4335 			mblk_t *dmp, *dmp_cont;
4336 
4337 			/*
4338 			 * If the user didn't supply any information,
4339 			 * NAK it.
4340 			 */
4341 			error = miocpullup(mp, sizeof (struct eucioc));
4342 			if (error != 0) {
4343 				miocnak(q, mp, 0, error);
4344 				return;
4345 			}
4346 
4347 			euciocp = (struct eucioc *)mp->b_cont->b_rptr;
4348 			/*
4349 			 * Check here for something reasonable.  If
4350 			 * anything will take more than EUC_MAXW
4351 			 * columns or more than EUC_MAXW bytes
4352 			 * following SS2 or SS3, then just reject it
4353 			 * out of hand. It's not impossible for us to
4354 			 * do it, it just isn't reasonable.  So far,
4355 			 * in the world, we've seen the absolute max
4356 			 * columns to be 2 and the max number of
4357 			 * bytes to be 3.  This allows room for some
4358 			 * expansion of that, but it probably won't
4359 			 * even be necessary. At the moment, we
4360 			 * return a "range" error.  If you really
4361 			 * need to, you can push EUC_MAXW up to over
4362 			 * 200; it doesn't make sense, though, with
4363 			 * only a CANBSIZ sized input limit (usually
4364 			 * 256)!
4365 			 */
4366 			for (i = 0; i < 4; i++) {
4367 				if ((euciocp->eucw[i] > EUC_MAXW) ||
4368 				    (euciocp->scrw[i] > EUC_MAXW)) {
4369 					miocnak(q, mp, 0, ERANGE);
4370 					return;
4371 				}
4372 			}
4373 			/*
4374 			 * Otherwise, save the information in tp,
4375 			 * force codeset 0 (ASCII) to be one byte,
4376 			 * one column.
4377 			 */
4378 			cp_eucwioc(euciocp, &tp->eucwioc, EUCIN);
4379 			tp->eucwioc.eucw[0] = tp->eucwioc.scrw[0] = 1;
4380 			/*
4381 			 * Now, check out whether we're doing
4382 			 * multibyte processing. if we are, we need
4383 			 * to allocate a block to hold the parallel
4384 			 * array. By convention, we've been passed
4385 			 * what amounts to a CSWIDTH definition.  We
4386 			 * actually NEED the number of bytes for
4387 			 * Codesets 2 & 3.
4388 			 */
4389 			tp->t_maxeuc = 0;	/* reset to say we're NOT */
4390 
4391 			tp->t_state &= ~TS_MEUC;
4392 			/*
4393 			 * We'll set TS_MEUC if we're doing
4394 			 * multi-column OR multi- byte OR both.  It
4395 			 * makes things easier...  NOTE:  If we fail
4396 			 * to get the buffer we need to hold display
4397 			 * widths, then DON'T let the TS_MEUC bit get
4398 			 * set!
4399 			 */
4400 			for (i = 0; i < 4; i++) {
4401 				if (tp->eucwioc.eucw[i] > tp->t_maxeuc)
4402 					tp->t_maxeuc = tp->eucwioc.eucw[i];
4403 				if (tp->eucwioc.scrw[i] > 1)
4404 					tp->t_state |= TS_MEUC;
4405 			}
4406 			if ((tp->t_maxeuc > 1) || (tp->t_state & TS_MEUC)) {
4407 				if (!tp->t_eucp_mp) {
4408 					if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
4409 					    BPRI_HI)) == NULL) {
4410 						tp->t_maxeuc = 1;
4411 						tp->t_state &= ~TS_MEUC;
4412 						cmn_err(CE_WARN,
4413 						    "Can't allocate eucp_mp");
4414 						miocnak(q, mp, 0, ENOSR);
4415 						return;
4416 					}
4417 					/*
4418 					 * here, if there's junk in
4419 					 * the canonical buffer, then
4420 					 * move the eucp pointer past
4421 					 * it, so we don't run off
4422 					 * the beginning.  This is a
4423 					 * total botch, but will
4424 					 * hopefully keep stuff from
4425 					 * getting too messed up
4426 					 * until the user flushes
4427 					 * this line!
4428 					 */
4429 					if (tp->t_msglen) {
4430 						tp->t_eucp =
4431 						    tp->t_eucp_mp->b_rptr;
4432 						for (i = tp->t_msglen; i; i--)
4433 							*tp->t_eucp++ = 1;
4434 					} else {
4435 						tp->t_eucp =
4436 						    tp->t_eucp_mp->b_rptr;
4437 					}
4438 				}
4439 				/* doing multi-byte handling */
4440 				tp->t_state |= TS_MEUC;
4441 
4442 			} else if (tp->t_eucp_mp) {
4443 				freemsg(tp->t_eucp_mp);
4444 				tp->t_eucp_mp = NULL;
4445 				tp->t_eucp = NULL;
4446 			}
4447 
4448 			/*
4449 			 * Save the EUC width data we have at
4450 			 * the t_csdata, set t_csdata.codeset_type to
4451 			 * EUC one, and, switch the codeset methods at
4452 			 * t_csmethods.
4453 			 */
4454 			bzero(&tp->t_csdata.eucpc_data,
4455 			    (sizeof (ldterm_eucpc_data_t) *
4456 			    LDTERM_CS_MAX_CODESETS));
4457 			tp->t_csdata.eucpc_data[0].byte_length =
4458 			    tp->eucwioc.eucw[1];
4459 			tp->t_csdata.eucpc_data[0].screen_width =
4460 			    tp->eucwioc.scrw[1];
4461 			tp->t_csdata.eucpc_data[1].byte_length =
4462 			    tp->eucwioc.eucw[2];
4463 			tp->t_csdata.eucpc_data[1].screen_width =
4464 			    tp->eucwioc.scrw[2];
4465 			tp->t_csdata.eucpc_data[2].byte_length =
4466 			    tp->eucwioc.eucw[3];
4467 			tp->t_csdata.eucpc_data[2].screen_width =
4468 			    tp->eucwioc.scrw[3];
4469 			tp->t_csdata.version = LDTERM_DATA_VERSION;
4470 			tp->t_csdata.codeset_type = LDTERM_CS_TYPE_EUC;
4471 			/*
4472 			 * We are not using the 'csinfo_num' anyway if the
4473 			 * current codeset type is EUC. So, set it to
4474 			 * the maximum possible.
4475 			 */
4476 			tp->t_csdata.csinfo_num =
4477 			    LDTERM_CS_TYPE_EUC_MAX_SUBCS;
4478 			if (tp->t_csdata.locale_name != (char *)NULL) {
4479 				kmem_free(tp->t_csdata.locale_name,
4480 				    strlen(tp->t_csdata.locale_name) + 1);
4481 				tp->t_csdata.locale_name = (char *)NULL;
4482 			}
4483 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
4484 
4485 			/*
4486 			 * If we are able to allocate two blocks (the
4487 			 * iocblk and the associated data), then pass
4488 			 * it downstream, otherwise we'll need to NAK
4489 			 * it, and drop whatever we WERE able to
4490 			 * allocate.
4491 			 */
4492 			if ((dmp = mkiocb(EUC_WSET)) == NULL) {
4493 				miocnak(q, mp, 0, ENOSR);
4494 				return;
4495 			}
4496 			if ((dmp_cont = allocb(EUCSIZE, BPRI_HI)) == NULL) {
4497 				freemsg(dmp);
4498 				miocnak(q, mp, 0, ENOSR);
4499 				return;
4500 			}
4501 
4502 			/*
4503 			 * We got both buffers.  Copy out the EUC
4504 			 * information (as we received it, not what
4505 			 * we're using!) & pass it on.
4506 			 */
4507 			bcopy(mp->b_cont->b_rptr, dmp_cont->b_rptr, EUCSIZE);
4508 			dmp_cont->b_wptr += EUCSIZE;
4509 			dmp->b_cont = dmp_cont;
4510 			dmp->b_datap->db_type = M_CTL;
4511 			dmp_cont->b_datap->db_type = M_DATA;
4512 			riocp = (struct iocblk *)dmp->b_rptr;
4513 			riocp->ioc_count = EUCSIZE;
4514 			putnext(q, dmp);
4515 
4516 			/*
4517 			 * Now ACK the ioctl.
4518 			 */
4519 			iocp->ioc_rval = 0;
4520 			miocack(q, mp, 0, 0);
4521 			return;
4522 		}
4523 
4524 	case EUC_WGET:
4525 		error = miocpullup(mp, sizeof (struct eucioc));
4526 		if (error != 0) {
4527 			miocnak(q, mp, 0, error);
4528 			return;
4529 		}
4530 		euciocp = (struct eucioc *)mp->b_cont->b_rptr;
4531 		cp_eucwioc(&tp->eucwioc, euciocp, EUCOUT);
4532 		iocp->ioc_rval = 0;
4533 		miocack(q, mp, EUCSIZE, 0);
4534 		return;
4535 
4536 	case CSDATA_SET:
4537 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
4538 		if (error != 0) {
4539 			miocnak(q, mp, 0, error);
4540 			return;
4541 		}
4542 
4543 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
4544 
4545 		/* Validate the codeset data provided. */
4546 		if (csdp->version > LDTERM_DATA_VERSION ||
4547 		    csdp->codeset_type < LDTERM_CS_TYPE_MIN ||
4548 		    csdp->codeset_type > LDTERM_CS_TYPE_MAX) {
4549 			miocnak(q, mp, 0, ERANGE);
4550 			return;
4551 		}
4552 
4553 		if ((csdp->codeset_type == LDTERM_CS_TYPE_EUC &&
4554 		    csdp->csinfo_num > LDTERM_CS_TYPE_EUC_MAX_SUBCS) ||
4555 		    (csdp->codeset_type == LDTERM_CS_TYPE_PCCS &&
4556 		    (csdp->csinfo_num < LDTERM_CS_TYPE_PCCS_MIN_SUBCS ||
4557 		    csdp->csinfo_num > LDTERM_CS_TYPE_PCCS_MAX_SUBCS))) {
4558 			miocnak(q, mp, 0, ERANGE);
4559 			return;
4560 		}
4561 
4562 		maxbytelen = maxscreenlen = 0;
4563 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4564 			for (i = 0; i < LDTERM_CS_TYPE_EUC_MAX_SUBCS; i++) {
4565 				if (csdp->eucpc_data[i].byte_length >
4566 				    EUC_MAXW ||
4567 				    csdp->eucpc_data[i].screen_width >
4568 				    EUC_MAXW) {
4569 					miocnak(q, mp, 0, ERANGE);
4570 					return;
4571 				}
4572 
4573 				if (csdp->eucpc_data[i].byte_length >
4574 				    maxbytelen)
4575 					maxbytelen =
4576 					    csdp->eucpc_data[i].byte_length;
4577 				if (csdp->eucpc_data[i].screen_width >
4578 				    maxscreenlen)
4579 					maxscreenlen =
4580 					    csdp->eucpc_data[i].screen_width;
4581 			}
4582 			/* POSIX/C locale? */
4583 			if (maxbytelen == 0 && maxscreenlen == 0)
4584 				maxbytelen = maxscreenlen = 1;
4585 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_PCCS) {
4586 			for (i = 0; i < LDTERM_CS_MAX_CODESETS; i++) {
4587 				if (csdp->eucpc_data[i].byte_length >
4588 				    LDTERM_CS_MAX_BYTE_LENGTH) {
4589 					miocnak(q, mp, 0, ERANGE);
4590 					return;
4591 				}
4592 				if (csdp->eucpc_data[i].byte_length >
4593 				    maxbytelen)
4594 					maxbytelen =
4595 					    csdp->eucpc_data[i].byte_length;
4596 				if (csdp->eucpc_data[i].screen_width >
4597 				    maxscreenlen)
4598 					maxscreenlen =
4599 					    csdp->eucpc_data[i].screen_width;
4600 			}
4601 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_UTF8) {
4602 			maxbytelen = 4;
4603 			maxscreenlen = 2;
4604 		}
4605 
4606 		locale_name_sz = 0;
4607 
4608 		for (i = 0; i < MAXNAMELEN; i++)
4609 			if (csdp->locale_name[i] == '\0')
4610 				break;
4611 		/*
4612 		 * We cannot have any string that is not NULL byte
4613 		 * terminated.
4614 		 */
4615 		if (i >= MAXNAMELEN) {
4616 			miocnak(q, mp, 0, ERANGE);
4617 			return;
4618 		}
4619 
4620 		locale_name_sz = i + 1;
4621 
4622 		/*
4623 		 * As the final check, if there was invalid codeset_type
4624 		 * given, or invalid byte_length was specified, it's an error.
4625 		 */
4626 		if (maxbytelen <= 0 || maxscreenlen <= 0) {
4627 			miocnak(q, mp, 0, ERANGE);
4628 			return;
4629 		}
4630 
4631 		/* Do the switching. */
4632 		tp->t_maxeuc = maxbytelen;
4633 		tp->t_state &= ~TS_MEUC;
4634 		if (maxbytelen > 1 || maxscreenlen > 1) {
4635 			if (!tp->t_eucp_mp) {
4636 				if (!(tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
4637 				    BPRI_HI))) {
4638 					cmn_err(CE_WARN,
4639 					    "Can't allocate eucp_mp");
4640 					miocnak(q, mp, 0, ENOSR);
4641 					return;
4642 				}
4643 				/*
4644 				 * If there's junk in the canonical buffer,
4645 				 * then move the eucp pointer past it,
4646 				 * so we don't run off the beginning. This is
4647 				 * a total botch, but will hopefully keep
4648 				 * stuff from getting too messed up until
4649 				 * the user flushes this line!
4650 				 */
4651 				if (tp->t_msglen) {
4652 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
4653 					for (i = tp->t_msglen; i; i--)
4654 						*tp->t_eucp++ = 1;
4655 				} else {
4656 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
4657 				}
4658 			}
4659 
4660 			/*
4661 			 * We only set TS_MEUC for a multibyte/multi-column
4662 			 * codeset.
4663 			 */
4664 			tp->t_state |= TS_MEUC;
4665 
4666 			tp->t_csdata.version = csdp->version;
4667 			tp->t_csdata.codeset_type = csdp->codeset_type;
4668 			tp->t_csdata.csinfo_num = csdp->csinfo_num;
4669 			bcopy(csdp->eucpc_data, tp->t_csdata.eucpc_data,
4670 			    sizeof (ldterm_eucpc_data_t) *
4671 			    LDTERM_CS_MAX_CODESETS);
4672 			tp->t_csmethods = cs_methods[csdp->codeset_type];
4673 
4674 			if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4675 				tp->eucwioc.eucw[0] = 1;
4676 				tp->eucwioc.scrw[0] = 1;
4677 
4678 				tp->eucwioc.eucw[1] =
4679 				    csdp->eucpc_data[0].byte_length;
4680 				tp->eucwioc.scrw[1] =
4681 				    csdp->eucpc_data[0].screen_width;
4682 
4683 				tp->eucwioc.eucw[2] =
4684 				    csdp->eucpc_data[1].byte_length + 1;
4685 				tp->eucwioc.scrw[2] =
4686 				    csdp->eucpc_data[1].screen_width;
4687 
4688 				tp->eucwioc.eucw[3] =
4689 				    csdp->eucpc_data[2].byte_length + 1;
4690 				tp->eucwioc.scrw[3] =
4691 				    csdp->eucpc_data[2].screen_width;
4692 			} else {
4693 				/*
4694 				 * We are not going to use this data
4695 				 * structure. So, clear it. Also, stty(1) will
4696 				 * make use of the cleared tp->eucwioc when
4697 				 * it prints out codeset width setting.
4698 				 */
4699 				bzero(&tp->eucwioc, EUCSIZE);
4700 			}
4701 		} else {
4702 			/*
4703 			 * If this codeset is a single byte codeset that
4704 			 * requires only single display column for all
4705 			 * characters, we switch to default EUC codeset
4706 			 * methods and data setting.
4707 			 */
4708 
4709 			if (tp->t_eucp_mp) {
4710 				freemsg(tp->t_eucp_mp);
4711 				tp->t_eucp_mp = NULL;
4712 				tp->t_eucp = NULL;
4713 			}
4714 
4715 			bzero(&tp->eucwioc, EUCSIZE);
4716 			tp->eucwioc.eucw[0] = 1;
4717 			tp->eucwioc.scrw[0] = 1;
4718 			if (tp->t_csdata.locale_name != (char *)NULL) {
4719 				kmem_free(tp->t_csdata.locale_name,
4720 				    strlen(tp->t_csdata.locale_name) + 1);
4721 			}
4722 			tp->t_csdata = default_cs_data;
4723 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
4724 		}
4725 
4726 		/* Copy over locale_name. */
4727 		if (tp->t_csdata.locale_name != (char *)NULL) {
4728 			kmem_free(tp->t_csdata.locale_name,
4729 			    strlen(tp->t_csdata.locale_name) + 1);
4730 		}
4731 		if (locale_name_sz > 1) {
4732 			tp->t_csdata.locale_name = (char *)kmem_alloc(
4733 			    locale_name_sz, KM_SLEEP);
4734 			(void) strcpy(tp->t_csdata.locale_name,
4735 			    csdp->locale_name);
4736 		} else {
4737 			tp->t_csdata.locale_name = (char *)NULL;
4738 		}
4739 
4740 		/*
4741 		 * Now ACK the ioctl.
4742 		 */
4743 		iocp->ioc_rval = 0;
4744 		miocack(q, mp, 0, 0);
4745 		return;
4746 
4747 	case CSDATA_GET:
4748 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
4749 		if (error != 0) {
4750 			miocnak(q, mp, 0, error);
4751 			return;
4752 		}
4753 
4754 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
4755 
4756 		csdp->version = tp->t_csdata.version;
4757 		csdp->codeset_type = tp->t_csdata.codeset_type;
4758 		csdp->csinfo_num = tp->t_csdata.csinfo_num;
4759 		csdp->pad = tp->t_csdata.pad;
4760 		if (tp->t_csdata.locale_name) {
4761 			(void) strcpy(csdp->locale_name,
4762 			    tp->t_csdata.locale_name);
4763 		} else {
4764 			csdp->locale_name[0] = '\0';
4765 		}
4766 		bcopy(tp->t_csdata.eucpc_data, csdp->eucpc_data,
4767 		    sizeof (ldterm_eucpc_data_t) * LDTERM_CS_MAX_CODESETS);
4768 		/*
4769 		 * If the codeset is an EUC codeset and if it has 2nd and/or
4770 		 * 3rd supplementary codesets, we subtract one from each
4771 		 * byte length of the supplementary codesets. This is
4772 		 * because single shift characters, SS2 and SS3, are not
4773 		 * included in the byte lengths in the user space.
4774 		 */
4775 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4776 			if (csdp->eucpc_data[1].byte_length)
4777 				csdp->eucpc_data[1].byte_length -= 1;
4778 			if (csdp->eucpc_data[2].byte_length)
4779 				csdp->eucpc_data[2].byte_length -= 1;
4780 		}
4781 		iocp->ioc_rval = 0;
4782 		miocack(q, mp, sizeof (ldterm_cs_data_user_t), 0);
4783 		return;
4784 
4785 	case PTSSTTY:
4786 		tp->t_state |= TS_ISPTSTTY;
4787 		break;
4788 
4789 	}
4790 
4791 	putnext(q, mp);
4792 }
4793 
4794 
4795 /*
4796  * Send an M_SETOPTS message upstream if any mode changes are being
4797  * made that affect the stream head options. returns -1 if allocb
4798  * fails, else returns 0.
4799  */
4800 static int
chgstropts(struct termios * oldmodep,ldtermstd_state_t * tp,queue_t * q)4801 chgstropts(struct termios *oldmodep, ldtermstd_state_t *tp, queue_t *q)
4802 {
4803 	struct stroptions optbuf;
4804 	mblk_t *bp;
4805 
4806 	optbuf.so_flags = 0;
4807 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & ICANON) {
4808 		/*
4809 		 * Canonical mode is changing state; switch the
4810 		 * stream head to message-nondiscard or byte-stream
4811 		 * mode.  Also, rerun the service procedure so it can
4812 		 * change its mind about whether to send data
4813 		 * upstream or not.
4814 		 */
4815 		if (tp->t_modes.c_lflag & ICANON) {
4816 			DEBUG4(("CHANGING TO CANON MODE\n"));
4817 			optbuf.so_flags = SO_READOPT|SO_MREADOFF;
4818 			optbuf.so_readopt = RMSGN;
4819 
4820 			/*
4821 			 * if there is a pending raw mode timeout,
4822 			 * clear it
4823 			 */
4824 
4825 			/*
4826 			 * Clear VMIN/VTIME state, cancel timers
4827 			 */
4828 			vmin_satisfied(q, tp, 0);
4829 		} else {
4830 			DEBUG4(("CHANGING TO RAW MODE\n"));
4831 			optbuf.so_flags = SO_READOPT|SO_MREADON;
4832 			optbuf.so_readopt = RNORM;
4833 		}
4834 	}
4835 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & TOSTOP) {
4836 		/*
4837 		 * The "stop on background write" bit is changing.
4838 		 */
4839 		if (tp->t_modes.c_lflag & TOSTOP)
4840 			optbuf.so_flags |= SO_TOSTOP;
4841 		else
4842 			optbuf.so_flags |= SO_TONSTOP;
4843 	}
4844 	if (optbuf.so_flags != 0) {
4845 		if ((bp = allocb(sizeof (struct stroptions), BPRI_HI)) ==
4846 		    NULL) {
4847 			return (-1);
4848 		}
4849 		*(struct stroptions *)bp->b_wptr = optbuf;
4850 		bp->b_wptr += sizeof (struct stroptions);
4851 		bp->b_datap->db_type = M_SETOPTS;
4852 		DEBUG4(("M_SETOPTS to stream head\n"));
4853 		putnext(q, bp);
4854 	}
4855 	return (0);
4856 }
4857 
4858 
4859 /*
4860  * Called when an M_IOCACK message is seen on the read queue;
4861  * modifies the data being returned, if necessary, and passes the
4862  * reply up.
4863  */
4864 static void
ldterm_ioctl_reply(queue_t * q,mblk_t * mp)4865 ldterm_ioctl_reply(queue_t *q, mblk_t *mp)
4866 {
4867 	ldtermstd_state_t *tp;
4868 	struct iocblk *iocp;
4869 
4870 	iocp = (struct iocblk *)mp->b_rptr;
4871 	tp = (ldtermstd_state_t *)q->q_ptr;
4872 
4873 	switch (iocp->ioc_cmd) {
4874 
4875 	case TCGETS:
4876 		{
4877 			/*
4878 			 * Get current parameters and return them to
4879 			 * stream head eventually.
4880 			 */
4881 			struct termios *cb =
4882 			    (struct termios *)mp->b_cont->b_rptr;
4883 
4884 			/*
4885 			 * cflag has cflags sent upstream by the
4886 			 * driver
4887 			 */
4888 			tcflag_t cflag = cb->c_cflag;
4889 
4890 			*cb = tp->t_amodes;
4891 			if (cflag != 0)
4892 				cb->c_cflag = cflag;	/* set by driver */
4893 			break;
4894 		}
4895 
4896 	case TCGETA:
4897 		{
4898 			/*
4899 			 * Old-style "ioctl" to get current
4900 			 * parameters and return them to stream head
4901 			 * eventually.
4902 			 */
4903 			struct termio *cb =
4904 			    (struct termio *)mp->b_cont->b_rptr;
4905 
4906 			cb->c_iflag = tp->t_amodes.c_iflag; /* all except the */
4907 			cb->c_oflag = tp->t_amodes.c_oflag; /* cb->c_cflag */
4908 			cb->c_lflag = tp->t_amodes.c_lflag;
4909 
4910 			if (cb->c_cflag == 0)	/* not set by driver */
4911 				cb->c_cflag = tp->t_amodes.c_cflag;
4912 
4913 			cb->c_line = 0;
4914 			bcopy(tp->t_amodes.c_cc, cb->c_cc, NCC);
4915 			break;
4916 		}
4917 	}
4918 	putnext(q, mp);
4919 }
4920 
4921 
4922 /*
4923  * A VMIN/VTIME request has been satisfied. Cancel outstanding timers
4924  * if they exist, clear TS_MREAD state, and send upstream. If a NULL
4925  * queue ptr is passed, just reset VMIN/VTIME state.
4926  */
4927 static void
vmin_satisfied(queue_t * q,ldtermstd_state_t * tp,int sendup)4928 vmin_satisfied(queue_t *q, ldtermstd_state_t *tp, int sendup)
4929 {
4930 	ASSERT(q);
4931 	if (tp->t_vtid != 0)  {
4932 		DEBUG4(("vmin_satisfied: cancelled timer id %d\n", tp->t_vtid));
4933 		(void) quntimeout(q, tp->t_vtid);
4934 		tp->t_vtid = 0;
4935 	}
4936 	if (sendup) {
4937 		if (tp->t_msglen == 0 && V_MIN) {
4938 			/* EMPTY */
4939 			DEBUG4(("vmin_satisfied: data swiped, msglen = 0\n"));
4940 		} else {
4941 			if ((!q->q_first) ||
4942 			    (q->q_first->b_datap->db_type != M_DATA) ||
4943 			    (tp->t_msglen >= LDCHUNK)) {
4944 				ldterm_msg_upstream(q, tp);
4945 				DEBUG4(("vmin_satisfied: delivering data\n"));
4946 			}
4947 		}
4948 	} else {
4949 		/* EMPTY */
4950 		DEBUG4(("vmin_satisfied: VMIN/TIME state reset\n"));
4951 	}
4952 	tp->t_state &= ~TS_MREAD;
4953 }
4954 
4955 static void
vmin_settimer(queue_t * q)4956 vmin_settimer(queue_t *q)
4957 {
4958 	ldtermstd_state_t *tp;
4959 
4960 	tp = (ldtermstd_state_t *)q->q_ptr;
4961 
4962 	/*
4963 	 * Don't start any time bombs.
4964 	 */
4965 	if (tp->t_state & TS_CLOSE)
4966 		return;
4967 
4968 	/*
4969 	 * tp->t_vtid should NOT be set here unless VMIN > 0 and
4970 	 * VTIME > 0.
4971 	 */
4972 	if (tp->t_vtid) {
4973 		if (V_MIN && V_TIME) {
4974 			/* EMPTY */
4975 			DEBUG4(("vmin_settimer: timer restarted, old tid=%d\n",
4976 			    tp->t_vtid));
4977 		} else {
4978 			/* EMPTY */
4979 			DEBUG4(("vmin_settimer: tid = %d was still active!\n",
4980 			    tp->t_vtid));
4981 		}
4982 		(void) quntimeout(q, tp->t_vtid);
4983 		tp->t_vtid = 0;
4984 	}
4985 	tp->t_vtid = qtimeout(q, vmin_timed_out, q,
4986 	    (clock_t)(V_TIME * (hz / 10)));
4987 	DEBUG4(("vmin_settimer: timer started, tid = %d\n", tp->t_vtid));
4988 }
4989 
4990 
4991 /*
4992  * BRRrrringgg!! VTIME was satisfied instead of VMIN
4993  */
4994 static void
vmin_timed_out(void * arg)4995 vmin_timed_out(void *arg)
4996 {
4997 	queue_t *q = arg;
4998 	ldtermstd_state_t *tp;
4999 
5000 	tp = (ldtermstd_state_t *)q->q_ptr;
5001 
5002 	DEBUG4(("vmin_timed_out: tid = %d\n", tp->t_vtid));
5003 	/* don't call untimeout now that we are in the timeout */
5004 	tp->t_vtid = 0;
5005 	vmin_satisfied(q, tp, 1);
5006 }
5007 
5008 
5009 /*
5010  * Routine to adjust termios flags to be processed by the line
5011  * discipline. Driver below sends a termios structure, with the flags
5012  * the driver intends to process. XOR'ing the driver sent termios
5013  * structure with current termios structure with the default values
5014  * (or set by ioctls from userland), we come up with a new termios
5015  * structrue, the flags of which will be used by the line discipline
5016  * in processing input and output. On return from this routine, we
5017  * will have the following fields set in tp structure -->
5018  * tp->t_modes:	modes the line discipline will process tp->t_amodes:
5019  * modes the user process thinks the line discipline is processing
5020  */
5021 
5022 static void
ldterm_adjust_modes(ldtermstd_state_t * tp)5023 ldterm_adjust_modes(ldtermstd_state_t *tp)
5024 {
5025 
5026 	DEBUG6(("original iflag = %o\n", tp->t_modes.c_iflag));
5027 	tp->t_modes.c_iflag = tp->t_amodes.c_iflag & ~(tp->t_dmodes.c_iflag);
5028 	tp->t_modes.c_oflag = tp->t_amodes.c_oflag & ~(tp->t_dmodes.c_oflag);
5029 	tp->t_modes.c_lflag = tp->t_amodes.c_lflag & ~(tp->t_dmodes.c_lflag);
5030 	DEBUG6(("driver iflag = %o\n", tp->t_dmodes.c_iflag));
5031 	DEBUG6(("apparent iflag = %o\n", tp->t_amodes.c_iflag));
5032 	DEBUG6(("effective iflag = %o\n", tp->t_modes.c_iflag));
5033 
5034 	/* No negotiation of clfags  c_cc array special characters */
5035 	/*
5036 	 * Copy from amodes to modes already done by TCSETA/TCSETS
5037 	 * code
5038 	 */
5039 }
5040 
5041 
5042 /*
5043  * Erase one multi-byte character.  If TS_MEUC is set AND this
5044  * is a multi-byte character, then this should be called instead of
5045  * ldterm_erase.  "ldterm_erase" will handle ASCII nicely, thank you.
5046  *
5047  * We'd better be pointing to the last byte.  If we aren't, it will get
5048  * screwed up.
5049  */
5050 static void
ldterm_csi_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)5051 ldterm_csi_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
5052 {
5053 	int i, ung;
5054 	uchar_t *p, *bottom;
5055 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
5056 	int c;
5057 	int j;
5058 	int len;
5059 
5060 	if (tp->t_eucleft) {
5061 		/* XXX Ick.  We're in the middle of an EUC! */
5062 		/* What to do now? */
5063 		ldterm_eucwarn(tp);
5064 		return;		/* ignore it??? */
5065 	}
5066 	bottom = tp->t_eucp_mp->b_rptr;
5067 	p = tp->t_eucp - 1;	/* previous byte */
5068 	if (p < bottom)
5069 		return;
5070 	ung = 1;		/* number of bytes to un-get from buffer */
5071 	/*
5072 	 * go through the buffer until we find the beginning of the
5073 	 * multi-byte char.
5074 	 */
5075 	while ((*p == 0) && (p > bottom)) {
5076 		p--;
5077 		++ung;
5078 	}
5079 
5080 	/*
5081 	 * Now, "ung" is the number of bytes to unget from the buffer
5082 	 * and "*p" is the disp width of it. Fool "ldterm_rubout"
5083 	 * into thinking we're rubbing out ASCII characters.  Do that
5084 	 * for the display width of the character.
5085 	 *
5086 	 * Also we accumulate bytes of the character so that if the character
5087 	 * is a UTF-8 character, we will get the display width of the UTF-8
5088 	 * character.
5089 	 */
5090 	if (ung >= LDTERM_CS_MAX_BYTE_LENGTH) {
5091 		j = len = LDTERM_CS_MAX_BYTE_LENGTH;
5092 	} else {
5093 		j = len = ung;
5094 	}
5095 	for (i = 0; i < ung; i++) {	/* remove from buf */
5096 		if ((c = ldterm_unget(tp)) != (-1)) {
5097 			ldterm_trim(tp);
5098 			if (j > 0)
5099 				u8[--j] = (uchar_t)c;
5100 		}
5101 	}
5102 	if (*p == UNKNOWN_WIDTH) {
5103 		if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_UTF8) {
5104 			*p = ldterm_utf8_width(u8, len);
5105 		} else {
5106 			*p = 1;
5107 		}
5108 	}
5109 	for (i = 0; i < (int)*p; i++)	/* remove from screen */
5110 		ldterm_rubout(' ', q, ebsize, tp);
5111 	/*
5112 	 * Adjust the parallel array pointer.  Zero out the contents
5113 	 * of parallel array for this position, just to make sure...
5114 	 */
5115 	tp->t_eucp = p;
5116 	*p = 0;
5117 }
5118 
5119 
5120 /*
5121  * This is kind of a safety valve.  Whenever we see a bad sequence
5122  * come up, we call eucwarn.  It just tallies the junk until a
5123  * threshold is reached.  Then it prints ONE message on the console
5124  * and not any more. Hopefully, we can catch garbage; maybe it will
5125  * be useful to somebody.
5126  */
5127 static void
ldterm_eucwarn(ldtermstd_state_t * tp)5128 ldterm_eucwarn(ldtermstd_state_t *tp)
5129 {
5130 	++tp->t_eucwarn;
5131 #ifdef DEBUG
5132 	if ((tp->t_eucwarn > EUC_WARNCNT) && !(tp->t_state & TS_WARNED)) {
5133 		cmn_err(CE_WARN,
5134 		    "ldterm: tty at addr %p in multi-byte mode --",
5135 		    (void *)tp);
5136 		cmn_err(CE_WARN,
5137 		    "Over %d bad EUC characters this session", EUC_WARNCNT);
5138 		tp->t_state |= TS_WARNED;
5139 	}
5140 #endif
5141 }
5142 
5143 
5144 /*
5145  * Copy an "eucioc_t" structure.  We use the structure with
5146  * incremented values for Codesets 2 & 3.  The specification in
5147  * eucioctl is that the sames values as the CSWIDTH definition at
5148  * user level are passed to us. When we copy it "in" to ourselves, we
5149  * do the increment.  That allows us to avoid treating each character
5150  * set separately for "t_eucleft" purposes. When we copy it "out" to
5151  * return it to the user, we decrement the values so the user gets
5152  * what it expects, and it matches CSWIDTH in the environment (if
5153  * things are consistent!).
5154  */
5155 static void
cp_eucwioc(eucioc_t * from,eucioc_t * to,int dir)5156 cp_eucwioc(eucioc_t *from, eucioc_t *to, int dir)
5157 {
5158 	bcopy(from, to, EUCSIZE);
5159 	if (dir == EUCOUT) {	/* copying out to user */
5160 		if (to->eucw[2])
5161 			--to->eucw[2];
5162 		if (to->eucw[3])
5163 			--to->eucw[3];
5164 	} else {		/* copying in */
5165 		if (to->eucw[2])
5166 			++to->eucw[2];
5167 		if (to->eucw[3])
5168 			++to->eucw[3];
5169 	}
5170 }
5171 
5172 
5173 /*
5174  * Take the first byte of a multi-byte, or an ASCII char.  Return its
5175  * codeset. If it's NOT the first byte of an EUC, then the return
5176  * value may be garbage, as it's probably not SS2 or SS3, and
5177  * therefore must be in codeset 1.  Another bizarre catch here is the
5178  * fact that we don't do anything about the "C1" control codes.  In
5179  * real life, we should; but nobody's come up with a good way of
5180  * treating them.
5181  */
5182 
5183 static int
ldterm_codeset(uchar_t codeset_type,uchar_t c)5184 ldterm_codeset(uchar_t codeset_type, uchar_t c)
5185 {
5186 
5187 	if (ISASCII(c))
5188 		return (0);
5189 
5190 	if (codeset_type != LDTERM_CS_TYPE_EUC)
5191 		return (1);
5192 
5193 	switch (c) {
5194 	case SS2:
5195 		return (2);
5196 	case SS3:
5197 		return (3);
5198 	default:
5199 		return (1);
5200 	}
5201 }
5202 
5203 /* The following two functions are additional EUC codeset specific methods. */
5204 /*
5205  * ldterm_dispwidth - Take the first byte of an EUC (or ASCII) and
5206  * return the display width.  Since this is intended mostly for
5207  * multi-byte handling, it returns EUC_TWIDTH for tabs so they can be
5208  * differentiated from EUC characters (assumption: EUC require fewer
5209  * than 255 columns).  Also, if it's a backspace and !flag, it
5210  * returns EUC_BSWIDTH.  Newline & CR also depend on flag.  This
5211  * routine SHOULD be cleaner than this, but we have the situation
5212  * where we may or may not be counting control characters as having a
5213  * column width. Therefore, the computation of ASCII is pretty messy.
5214  * The caller will be storing the value, and then switching on it
5215  * when it's used.  We really should define the EUC_TWIDTH and other
5216  * constants in a header so that the routine could be used in other
5217  * modules in the kernel.
5218  */
5219 static int
__ldterm_dispwidth_euc(uchar_t c,void * p,int mode)5220 __ldterm_dispwidth_euc(uchar_t c, void *p, int mode)
5221 {
5222 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5223 
5224 	if (ISASCII(c)) {
5225 		if (c <= '\037') {
5226 			switch (c) {
5227 			case '\t':
5228 				return (EUC_TWIDTH);
5229 			case '\b':
5230 				return (mode ? 2 : EUC_BSWIDTH);
5231 			case '\n':
5232 				return (EUC_NLWIDTH);
5233 			case '\r':
5234 				return (mode ? 2 : EUC_CRWIDTH);
5235 			default:
5236 				return (mode ? 2 : 0);
5237 			}
5238 		}
5239 		return (1);
5240 	}
5241 	switch (c) {
5242 	case SS2:
5243 		return (tp->eucwioc.scrw[2]);
5244 	case SS3:
5245 		return (tp->eucwioc.scrw[3]);
5246 	default:
5247 		return (tp->eucwioc.scrw[1]);
5248 	}
5249 }
5250 
5251 /*
5252  * ldterm_memwidth_euc - Take the first byte of an EUC (or an ASCII char)
5253  * and return its memory width.  The routine could have been
5254  * implemented to use only the codeset number, but that would require
5255  * the caller to have that value available.  Perhaps the user doesn't
5256  * want to make the extra call or keep the value of codeset around.
5257  * Therefore, we use the actual character with which they're
5258  * concerned.  This should never be called with anything but the
5259  * first byte of an EUC, otherwise it will return a garbage value.
5260  */
5261 static int
__ldterm_memwidth_euc(uchar_t c,void * p)5262 __ldterm_memwidth_euc(uchar_t c, void *p)
5263 {
5264 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5265 
5266 	if (ISASCII(c))
5267 		return (1);
5268 	switch (c) {
5269 	case SS2:
5270 		return (tp->eucwioc.eucw[2]);
5271 	case SS3:
5272 		return (tp->eucwioc.eucw[3]);
5273 	default:
5274 		return (tp->eucwioc.eucw[1]);
5275 	}
5276 }
5277 
5278 
5279 /* The following two functions are PCCS codeset specific methods. */
5280 static int
__ldterm_dispwidth_pccs(uchar_t c,void * p,int mode)5281 __ldterm_dispwidth_pccs(uchar_t c, void *p, int mode)
5282 {
5283 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5284 	int i;
5285 
5286 	if (ISASCII(c)) {
5287 		if (c <= '\037') {
5288 			switch (c) {
5289 			case '\t':
5290 				return (EUC_TWIDTH);
5291 			case '\b':
5292 				return (mode ? 2 : EUC_BSWIDTH);
5293 			case '\n':
5294 				return (EUC_NLWIDTH);
5295 			case '\r':
5296 				return (mode ? 2 : EUC_CRWIDTH);
5297 			default:
5298 				return (mode ? 2 : 0);
5299 			}
5300 		}
5301 		return (1);
5302 	}
5303 
5304 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
5305 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
5306 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
5307 			return (tp->t_csdata.eucpc_data[i].screen_width);
5308 	}
5309 
5310 	/*
5311 	 * If this leading byte is not in the range list, either provided
5312 	 * locale data is not sufficient or we encountered an invalid
5313 	 * character. We return 1 in this case as a fallback value.
5314 	 */
5315 	return (1);
5316 }
5317 
5318 static int
__ldterm_memwidth_pccs(uchar_t c,void * p)5319 __ldterm_memwidth_pccs(uchar_t c, void *p)
5320 {
5321 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5322 	int i;
5323 
5324 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
5325 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
5326 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
5327 			return (tp->t_csdata.eucpc_data[i].byte_length);
5328 	}
5329 
5330 	/*
5331 	 * If this leading byte is not in the range list, either provided
5332 	 * locale data is not sufficient or we encountered an invalid
5333 	 * character. We return 1 in this case as a fallback value.
5334 	 */
5335 	return (1);
5336 }
5337 
5338 
5339 /* The following two functions are UTF-8 codeset specific methods. */
5340 static int
__ldterm_dispwidth_utf8(uchar_t c,void * p,int mode)5341 __ldterm_dispwidth_utf8(uchar_t c, void *p, int mode)
5342 {
5343 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5344 
5345 	if (ISASCII(c)) {
5346 		if (c <= '\037') {
5347 			switch (c) {
5348 			case '\t':
5349 				return (EUC_TWIDTH);
5350 			case '\b':
5351 				return (mode ? 2 : EUC_BSWIDTH);
5352 			case '\n':
5353 				return (EUC_NLWIDTH);
5354 			case '\r':
5355 				return (mode ? 2 : EUC_CRWIDTH);
5356 			default:
5357 				return (mode ? 2 : 0);
5358 			}
5359 		}
5360 		return (1);
5361 	}
5362 
5363 	/* This is to silence the lint. */
5364 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
5365 		return (1);
5366 
5367 	/*
5368 	 * If it is a valid leading byte of a UTF-8 character, we set
5369 	 * the width as 'UNKNOWN_WIDTH' for now. We need to have all
5370 	 * the bytes to figure out the display width.
5371 	 */
5372 	if (c >= (uchar_t)0xc0 && c <= (uchar_t)0xfd)
5373 		return (UNKNOWN_WIDTH);
5374 
5375 	/*
5376 	 * If it is an invalid leading byte, we just do our best by
5377 	 * giving the display width of 1.
5378 	 */
5379 	return (1);
5380 }
5381 
5382 
5383 static int
__ldterm_memwidth_utf8(uchar_t c,void * p)5384 __ldterm_memwidth_utf8(uchar_t c, void *p)
5385 {
5386 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5387 	int len;
5388 
5389 	/*
5390 	 * If the codeset type doesn't match, we treat them as
5391 	 * an illegal character and return 1.
5392 	 */
5393 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
5394 		return (1);
5395 
5396 	len = u8_number_of_bytes[c];
5397 
5398 	/*
5399 	 * If this is a start of an illegal character, we treat
5400 	 * such as an 1 byte character and screen out.
5401 	 */
5402 	return ((len <= 0) ? 1 : len);
5403 }
5404 
5405 static uchar_t
ldterm_utf8_width(uchar_t * u8,int length)5406 ldterm_utf8_width(uchar_t *u8, int length)
5407 {
5408 	int i;
5409 	int j;
5410 	uint_t intcode = 0;
5411 
5412 	if (length == 0)
5413 		return ('\0');
5414 
5415 	j = u8_number_of_bytes[u8[0]] - 1;
5416 
5417 	/*
5418 	 * If the UTF-8 character is out of UTF-16 code range, or,
5419 	 * if it is either an ASCII character or an invalid leading byte for
5420 	 * a UTF-8 character, return 1.
5421 	 */
5422 	if (length > 4 || j <= 0)
5423 		return ('\1');
5424 
5425 	intcode = u8[0] & u8_masks_tbl[j];
5426 	for (i = 1; j > 0; j--, i++) {
5427 		/*
5428 		 * The following additional checking is needed to conform to
5429 		 * the "UTF-8 Corrigendum" introduced at the Unicode 3.1 and
5430 		 * then updated one more time at the Unicode 3.2.
5431 		 */
5432 		if (i == 1) {
5433 			if (u8[i] < u8_valid_min_2nd_byte[u8[0]] ||
5434 			    u8[i] > u8_valid_max_2nd_byte[u8[0]])
5435 				return ('\1');
5436 		} else if (u8[i] < (uchar_t)LDTERM_CS_TYPE_UTF8_MIN_BYTE ||
5437 		    u8[i] > (uchar_t)LDTERM_CS_TYPE_UTF8_MAX_BYTE)
5438 			return ('\1');
5439 
5440 		/*
5441 		 * All subsequent bytes of UTF-8 character has the following
5442 		 * binary encoding:
5443 		 *
5444 		 * 10xx xxxx
5445 		 *
5446 		 * hence left shift six bits to make space and then get
5447 		 * six bits from the new byte.
5448 		 */
5449 		intcode = (intcode << LDTERM_CS_TYPE_UTF8_SHIFT_BITS) |
5450 		    (u8[i] & LDTERM_CS_TYPE_UTF8_BIT_MASK);
5451 	}
5452 
5453 	i = 0;
5454 	if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P00) {
5455 		/* Basic Multilingual Plane. */
5456 		i = intcode / 4;
5457 		j = intcode % 4;
5458 		switch (j) {
5459 		case 0:
5460 			i = ldterm_ucode[0][i].u0;
5461 			break;
5462 		case 1:
5463 			i = ldterm_ucode[0][i].u1;
5464 			break;
5465 		case 2:
5466 			i = ldterm_ucode[0][i].u2;
5467 			break;
5468 		case 3:
5469 			i = ldterm_ucode[0][i].u3;
5470 			break;
5471 		}
5472 	} else if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P01) {
5473 		/* Secondary Multilingual Plane. */
5474 		intcode = intcode & (uint_t)0xffff;
5475 		i = intcode / 4;
5476 		j = intcode % 4;
5477 		switch (j) {
5478 		case 0:
5479 			i = ldterm_ucode[1][i].u0;
5480 			break;
5481 		case 1:
5482 			i = ldterm_ucode[1][i].u1;
5483 			break;
5484 		case 2:
5485 			i = ldterm_ucode[1][i].u2;
5486 			break;
5487 		case 3:
5488 			i = ldterm_ucode[1][i].u3;
5489 			break;
5490 		}
5491 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKEXTB &&
5492 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKEXTB) ||
5493 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKCOMP &&
5494 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKCOMP) ||
5495 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P15 &&
5496 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P15) ||
5497 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P16 &&
5498 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P16)) {
5499 		/*
5500 		 * Supplementary Plane for CJK Ideographs and
5501 		 * Private Use Planes.
5502 		 */
5503 		return ('\2');
5504 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_P14 &&
5505 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P14) ||
5506 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_VARSEL &&
5507 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_VARSEL)) {
5508 		/*
5509 		 * Some Special Purpose Plane characters:
5510 		 * These are like control characters and not printable.
5511 		 */
5512 		return ('\0');
5513 	}
5514 
5515 	/*
5516 	 * We return the display width of 1 for all character code points
5517 	 * that we didn't catch from the above logic and also for combining
5518 	 * and conjoining characters with width value of zero.
5519 	 *
5520 	 * In particular, the reason why we are returning 1 for combining
5521 	 * and conjoining characters is because the GUI-based terminal
5522 	 * emulators are not yet capable of properly handling such characters
5523 	 * and in most of the cases, they just treat such characters as if
5524 	 * they occupy a display cell. If the terminal emulators are capable of
5525 	 * handling the characters correctly, then, this logic of returning
5526 	 * 1 should be revisited and changed. See CR 6660526 for more
5527 	 * details on this.
5528 	 */
5529 	return ((i == 0) ? '\1' : (uchar_t)i);
5530 }
5531