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