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