Print this page
7127 remove -Wno-missing-braces from Makefile.uts
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",
↓ open down ↓ |
382 lines elided |
↑ open up ↑ |
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 - MODREV_1, &modlstrmod, NULL
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
↓ open down ↓ |
94 lines elided |
↑ open up ↑ |
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 - '\0', '\0', '\0', '\0',
509 - '\0', '\0', '\0', '\0',
510 - '\0', '\0', '\0', '\0',
511 - '\0', '\0', '\0', '\0',
512 - '\0', '\0', '\0', '\0',
513 - '\0', '\0', '\0', '\0',
514 - '\0', '\0', '\0', '\0',
515 - '\0', '\0', '\0', '\0',
516 - '\0', '\0', '\0', '\0',
517 - '\0', '\0', '\0', '\0'
508 + { '\0', '\0', '\0', '\0' },
509 + { '\0', '\0', '\0', '\0' },
510 + { '\0', '\0', '\0', '\0' },
511 + { '\0', '\0', '\0', '\0' },
512 + { '\0', '\0', '\0', '\0' },
513 + { '\0', '\0', '\0', '\0' },
514 + { '\0', '\0', '\0', '\0' },
515 + { '\0', '\0', '\0', '\0' },
516 + { '\0', '\0', '\0', '\0' },
517 + { '\0', '\0', '\0', '\0' }
518 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
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 569 256,
570 570 HIWAT,
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
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 796 strop->so_hiwat = HIWAT;
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]) {
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
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 1898 if ((tp->t_msglen > ((MAX_CANON + 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
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 4386 if (!(tp->t_eucp_mp = allocb(CANBSIZ,
4387 4387 BPRI_HI))) {
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 */
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 4615 if (!(tp->t_eucp_mp = allocb(CANBSIZ,
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 ↓ |
4982 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX