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