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