Print this page
8368 remove warlock leftovers from usr/src/uts
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/uts/common/io/vcons.c
+++ new/usr/src/uts/common/io/vcons.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
24 24 */
25 25
26 26 #include <sys/types.h>
27 27 #include <sys/param.h>
28 28 #include <sys/signal.h>
29 29 #include <sys/cred.h>
30 30 #include <sys/vnode.h>
31 31 #include <sys/termios.h>
32 32 #include <sys/termio.h>
33 33 #include <sys/ttold.h>
34 34 #include <sys/stropts.h>
35 35 #include <sys/stream.h>
36 36 #include <sys/strsun.h>
37 37 #include <sys/tty.h>
38 38 #include <sys/buf.h>
39 39 #include <sys/uio.h>
40 40 #include <sys/stat.h>
41 41 #include <sys/sysmacros.h>
42 42 #include <sys/errno.h>
43 43 #include <sys/proc.h>
44 44 #include <sys/procset.h>
45 45 #include <sys/fault.h>
46 46 #include <sys/siginfo.h>
47 47 #include <sys/debug.h>
48 48 #include <sys/kd.h>
49 49 #include <sys/vt.h>
50 50 #include <sys/vtdaemon.h>
51 51 #include <sys/session.h>
52 52 #include <sys/door.h>
53 53 #include <sys/kmem.h>
54 54 #include <sys/cpuvar.h>
55 55 #include <sys/kbio.h>
56 56 #include <sys/strredir.h>
57 57 #include <sys/fs/snode.h>
58 58 #include <sys/consdev.h>
59 59 #include <sys/conf.h>
60 60 #include <sys/cmn_err.h>
61 61 #include <sys/console.h>
62 62 #include <sys/promif.h>
63 63 #include <sys/note.h>
64 64 #include <sys/polled_io.h>
65 65 #include <sys/systm.h>
66 66 #include <sys/ddi.h>
67 67 #include <sys/sunddi.h>
68 68 #include <sys/sunndi.h>
69 69 #include <sys/esunddi.h>
70 70 #include <sys/sunldi.h>
71 71 #include <sys/debug.h>
72 72 #include <sys/console.h>
73 73 #include <sys/ddi_impldefs.h>
74 74 #include <sys/policy.h>
75 75 #include <sys/tem.h>
76 76 #include <sys/wscons.h>
77 77 #include <sys/systm.h>
78 78 #include <sys/modctl.h>
79 79 #include <sys/vt_impl.h>
80 80 #include <sys/consconfig_dacf.h>
81 81
82 82 /*
83 83 * This file belongs to wc STREAMS module which has a D_MTPERMODE
84 84 * inner perimeter. See "Locking Policy" comment in wscons.c for
85 85 * more information.
86 86 */
87 87
88 88 /*
89 89 * Minor name device file Hotkeys
90 90 *
91 91 * 0 the system console /dev/console Alt + F1
92 92 * 0: virtual console #1 /dev/vt/0 Alt + F1
93 93 *
94 94 * 2: virtual console #2 /dev/vt/2 Alt + F2
95 95 * 3: virtual console #3 /dev/vt/3 Alt + F3
96 96 * ......
97 97 * n: virtual console #n /dev/vt/n Alt + Fn
98 98 *
99 99 * Note that vtdaemon is running on /dev/vt/1 (minor=1),
100 100 * which is not available to end users.
101 101 *
102 102 */
103 103
104 104 #define VT_DAEMON_MINOR 1
105 105 #define VT_IS_DAEMON(minor) ((minor) == VT_DAEMON_MINOR)
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
106 106
107 107 extern void wc_get_size(vc_state_t *pvc);
108 108 extern boolean_t consconfig_console_is_tipline(void);
109 109
110 110
111 111 minor_t vc_last_console = VT_MINOR_INVALID; /* the last used console */
112 112 volatile uint_t vc_target_console; /* arg (1..n) */
113 113
114 114 static volatile minor_t vc_inuse_max_minor = 0;
115 115 static list_t vc_waitactive_list;
116 -_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_target_console))
117 -_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_last_console))
118 -_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_inuse_max_minor))
119 -_NOTE(SCHEME_PROTECTS_DATA("D_MTPERMOD protected data", vc_waitactive_list))
120 116
121 117 static int vt_pending_vtno = -1;
122 118 kmutex_t vt_pending_vtno_lock;
123 -_NOTE(MUTEX_PROTECTS_DATA(vt_pending_vtno_lock, vt_pending_vtno))
124 119
125 120 static int vt_activate(uint_t vt_no, cred_t *credp);
126 121 static void vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size);
127 122 static void vt_copyin(queue_t *qp, mblk_t *mp, uint_t size);
128 123 static void vt_iocnak(queue_t *qp, mblk_t *mp, int error);
129 124 static void vt_iocack(queue_t *qp, mblk_t *mp);
130 125
131 126 static uint_t vt_minor2arg(minor_t minor);
132 127 static minor_t vt_arg2minor(uint_t arg);
133 128
134 129 /*
135 130 * If the system console is directed to tipline, consider /dev/vt/0 as
136 131 * not being used.
137 132 * For other VT, if it is opened and tty is initialized, consider it
138 133 * as being used.
139 134 */
140 135 #define VT_IS_INUSE(id) \
141 136 (((vt_minor2vc(id))->vc_flags & WCS_ISOPEN) && \
142 137 ((vt_minor2vc(id))->vc_flags & WCS_INIT) && \
143 138 (id != 0 || !consconfig_console_is_tipline()))
144 139
145 140 /*
146 141 * the vt switching message is encoded as:
147 142 *
148 143 * -------------------------------------------------------------
149 144 * | \033 | 'Q' | vtno + 'A' | opcode | 'z' | '\0' |
150 145 * -------------------------------------------------------------
151 146 */
152 147 #define VT_MSG_SWITCH(mp) \
153 148 ((int)((mp)->b_wptr - (mp)->b_rptr) >= 5 && \
154 149 *((mp)->b_rptr) == '\033' && \
155 150 *((mp)->b_rptr + 1) == 'Q' && \
156 151 *((mp)->b_rptr + 4) == 'z')
157 152
158 153 #define VT_MSG_VTNO(mp) (*((mp)->b_rptr + 2) - 'A')
159 154 #define VT_MSG_OPCODE(mp) (*((mp)->b_rptr + 3))
160 155
161 156 #define VT_DOORCALL_MAX_RETRY 3
162 157
163 158 static void
164 159 vt_init_ttycommon(tty_common_t *pcommon)
165 160 {
166 161 struct termios *termiosp;
167 162 int len;
168 163
169 164 mutex_init(&pcommon->t_excl, NULL, MUTEX_DEFAULT, NULL);
170 165 pcommon->t_iflag = 0;
171 166
172 167 /*
173 168 * Get the default termios settings (cflag).
174 169 * These are stored as a property in the
175 170 * "options" node.
176 171 */
177 172 if (ddi_getlongprop(DDI_DEV_T_ANY,
178 173 ddi_root_node(), 0, "ttymodes",
179 174 (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS) {
180 175
181 176 if (len == sizeof (struct termios))
182 177 pcommon->t_cflag = termiosp->c_cflag;
183 178 else
184 179 cmn_err(CE_WARN,
185 180 "wc: Couldn't get ttymodes property!");
186 181
187 182 kmem_free(termiosp, len);
188 183 } else {
189 184 /*
190 185 * Gack! Whine about it.
191 186 */
192 187 cmn_err(CE_WARN,
193 188 "wc: Couldn't get ttymodes property!");
194 189 }
195 190
196 191 pcommon->t_iocpending = NULL;
197 192 }
198 193
199 194 static int
200 195 vt_config(uint_t count)
201 196 {
202 197 if (consmode != CONS_KFB)
203 198 return (ENOTSUP);
204 199
205 200 /* one for system console, one for vtdaemon */
206 201 if (count < 2)
207 202 return (ENXIO);
208 203
209 204 /*
210 205 * Shouldn't allow to shrink the max vt minor to be smaller than
211 206 * the max in used minor.
212 207 */
213 208 if (count <= vc_inuse_max_minor)
214 209 return (EBUSY);
215 210
216 211 mutex_enter(&vc_lock);
217 212 vt_resize(count);
218 213 mutex_exit(&vc_lock);
219 214
220 215 return (0);
221 216 }
222 217
223 218 void
224 219 vt_clean(queue_t *q, vc_state_t *pvc)
225 220 {
226 221 ASSERT(MUTEX_HELD(&pvc->vc_state_lock));
227 222
228 223 if (pvc->vc_bufcallid != 0) {
229 224 qunbufcall(q, pvc->vc_bufcallid);
230 225 pvc->vc_bufcallid = 0;
231 226 }
232 227 if (pvc->vc_timeoutid != 0) {
233 228 (void) quntimeout(q, pvc->vc_timeoutid);
234 229 pvc->vc_timeoutid = 0;
235 230 }
236 231 ttycommon_close(&pvc->vc_ttycommon);
237 232
238 233 pvc->vc_flags &= ~WCS_INIT;
239 234 }
240 235
241 236 /*
242 237 * Reply the VT_WAITACTIVE ioctl.
243 238 * Argument 'close' usage:
244 239 * B_TRUE: the vt designated by argument 'minor' is being closed.
245 240 * B_FALSE: the vt designated by argument 'minor' has been activated just now.
246 241 */
247 242 static void
248 243 vc_waitactive_reply(int minor, boolean_t close)
249 244 {
250 245 vc_waitactive_msg_t *index, *tmp;
251 246 vc_state_t *pvc;
252 247
253 248 index = list_head(&vc_waitactive_list);
254 249
255 250 while (index != NULL) {
256 251 tmp = index;
257 252 index = list_next(&vc_waitactive_list, index);
258 253
259 254 if ((close && tmp->wa_msg_minor == minor) ||
260 255 (!close && tmp->wa_wait_minor == minor)) {
261 256 list_remove(&vc_waitactive_list, tmp);
262 257 pvc = vt_minor2vc(tmp->wa_msg_minor);
263 258
264 259 if (close)
265 260 vt_iocnak(pvc->vc_wq, tmp->wa_mp, ENXIO);
266 261 else
267 262 vt_iocack(pvc->vc_wq, tmp->wa_mp);
268 263
269 264 kmem_free(tmp, sizeof (vc_waitactive_msg_t));
270 265 }
271 266 }
272 267 }
273 268
274 269 void
275 270 vt_close(queue_t *q, vc_state_t *pvc, cred_t *credp)
276 271 {
277 272 minor_t index;
278 273
279 274 mutex_enter(&pvc->vc_state_lock);
280 275 vt_clean(q, pvc);
281 276 pvc->vc_flags &= ~WCS_ISOPEN;
282 277 mutex_exit(&pvc->vc_state_lock);
283 278
284 279 tem_destroy(pvc->vc_tem, credp);
285 280 pvc->vc_tem = NULL;
286 281
287 282 index = pvc->vc_minor;
288 283 if (index == vc_inuse_max_minor) {
289 284 while ((--index > 0) && !VT_IS_INUSE(index))
290 285 ;
291 286 vc_inuse_max_minor = index;
292 287 }
293 288
294 289 vc_waitactive_reply(pvc->vc_minor, B_TRUE);
295 290 }
296 291
297 292 static void
298 293 vt_init_tty(vc_state_t *pvc)
299 294 {
300 295 ASSERT(MUTEX_HELD(&pvc->vc_state_lock));
301 296
302 297 pvc->vc_flags |= WCS_INIT;
303 298 vt_init_ttycommon(&pvc->vc_ttycommon);
304 299 wc_get_size(pvc);
305 300 }
306 301
307 302 /*
308 303 * minor 0: /dev/vt/0 (index = 0, indicating the system console)
309 304 * minor 1: /dev/vt/1 (index = 1, vtdaemon special console)
310 305 * minor 2: /dev/vt/2 (index = 2, virtual consoles)
311 306 * ......
312 307 * minor n: /dev/vt/n (index = n)
313 308 *
314 309 *
315 310 * The system console (minor 0), is opened firstly and used during console
316 311 * configuration. It also acts as the system hard console even when all
317 312 * virtual consoles go off.
318 313 *
319 314 * In tipline case, minor 0 (/dev/vt/0) is reserved, and cannot be switched to.
320 315 * And the system console is redirected to the tipline. During normal cases,
321 316 * we can switch from virtual consoles to it by pressing 'Alt + F1'.
322 317 *
323 318 * minor 1 (/dev/vt/1) is reserved for vtdaemon special console, and it's
324 319 * not available to end users.
325 320 *
326 321 * During early console configuration, consconfig_dacf opens wscons and then
327 322 * issue a WC_OPEN_FB ioctl to kick off terminal init process. So during
328 323 * consconfig_dacf first opening of wscons, tems (of type tem_state_t) is
329 324 * not initialized. We do not initialize the tem_vt_state_t instance returned
330 325 * by tem_init() for this open, since we do not have enough info to handle
331 326 * normal terminal operation at this moment. This tem_vt_state_t instance
332 327 * will get initialized when handling WC_OPEN_FB.
333 328 */
334 329 int
335 330 vt_open(minor_t minor, queue_t *rq, cred_t *crp)
336 331 {
337 332 vc_state_t *pvc;
338 333
339 334 if (!vt_minor_valid(minor))
340 335 return (ENXIO);
341 336
342 337 pvc = vt_minor2vc(minor);
343 338 if (pvc == NULL)
344 339 return (ENXIO);
345 340
346 341 mutex_enter(&vc_lock);
347 342 mutex_enter(&pvc->vc_state_lock);
348 343
349 344 if (!(pvc->vc_flags & WCS_ISOPEN)) {
350 345 /*
351 346 * vc_tem might not be intialized if !tems.ts_initialized,
352 347 * and this only happens during console configuration.
353 348 */
354 349 pvc->vc_tem = tem_init(crp);
355 350 }
356 351
357 352 if (!(pvc->vc_flags & WCS_INIT))
358 353 vt_init_tty(pvc);
359 354
360 355 /*
361 356 * In normal case, the first screen is the system console;
362 357 * In tipline case, the first screen is the first VT that gets started.
363 358 */
364 359 if (vc_active_console == VT_MINOR_INVALID && minor != VT_DAEMON_MINOR)
365 360 if (minor == 0 || consmode == CONS_KFB) {
366 361 boolean_t unblank = B_FALSE;
367 362
368 363 vc_active_console = minor;
369 364 vc_last_console = minor;
370 365 if (minor != 0) {
371 366 /*
372 367 * If we are not opening the system console
373 368 * as the first console, clear the phyical
374 369 * screen.
375 370 */
376 371 unblank = B_TRUE;
377 372 }
378 373
379 374 tem_activate(pvc->vc_tem, unblank, crp);
380 375 }
381 376
382 377 if ((pvc->vc_ttycommon.t_flags & TS_XCLUDE) &&
383 378 (secpolicy_excl_open(crp) != 0)) {
384 379 mutex_exit(&pvc->vc_state_lock);
385 380 mutex_exit(&vc_lock);
386 381 return (EBUSY);
387 382 }
388 383
389 384 if (minor > vc_inuse_max_minor)
390 385 vc_inuse_max_minor = minor;
391 386
392 387 pvc->vc_flags |= WCS_ISOPEN;
393 388 pvc->vc_ttycommon.t_readq = rq;
394 389 pvc->vc_ttycommon.t_writeq = WR(rq);
395 390
396 391 mutex_exit(&pvc->vc_state_lock);
397 392 mutex_exit(&vc_lock);
398 393
399 394 rq->q_ptr = pvc;
400 395 WR(rq)->q_ptr = pvc;
401 396 pvc->vc_wq = WR(rq);
402 397
403 398 qprocson(rq);
404 399 return (0);
405 400 }
406 401
407 402 static minor_t
408 403 vt_find_prev(minor_t cur)
409 404 {
410 405 minor_t i, t, max;
411 406
412 407 ASSERT(vc_active_console != VT_MINOR_INVALID);
413 408
414 409 max = VC_INSTANCES_COUNT;
415 410
416 411 for (i = cur - 1; (t = (i + max) % max) != cur; i--)
417 412 if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t))
418 413 return (t);
419 414
420 415 return (VT_MINOR_INVALID);
421 416 }
422 417
423 418 static minor_t
424 419 vt_find_next(minor_t cur)
425 420 {
426 421 minor_t i, t, max;
427 422
428 423 ASSERT(vc_active_console != VT_MINOR_INVALID);
429 424
430 425 max = VC_INSTANCES_COUNT;
431 426
432 427 for (i = cur + 1; (t = (i + max) % max) != cur; i++)
433 428 if (!VT_IS_DAEMON(t) && VT_IS_INUSE(t))
434 429 return (t);
435 430
436 431 return (VT_MINOR_INVALID);
437 432 }
438 433
439 434 /* ARGSUSED */
440 435 void
441 436 vt_send_hotkeys(void *timeout_arg)
442 437 {
443 438 door_handle_t door;
444 439 vt_cmd_arg_t arg;
445 440 int error = 0;
446 441 int retries = 0;
447 442 door_arg_t door_arg;
448 443
449 444 arg.vt_ev = VT_EV_HOTKEYS;
450 445
451 446 mutex_enter(&vt_pending_vtno_lock);
452 447 arg.vt_num = vt_pending_vtno;
453 448 mutex_exit(&vt_pending_vtno_lock);
454 449
455 450 /* only available in kernel context or user context */
456 451 if (door_ki_open(VT_DAEMON_DOOR_FILE, &door) != 0) {
457 452 mutex_enter(&vt_pending_vtno_lock);
458 453 vt_pending_vtno = -1;
459 454 mutex_exit(&vt_pending_vtno_lock);
460 455 return;
461 456 }
462 457
463 458 door_arg.rbuf = NULL;
464 459 door_arg.rsize = 0;
465 460 door_arg.data_ptr = (void *)&arg;
466 461 door_arg.data_size = sizeof (arg);
467 462 door_arg.desc_ptr = NULL;
468 463 door_arg.desc_num = 0;
469 464
470 465 /*
471 466 * Make door upcall
472 467 */
473 468 while ((error = door_ki_upcall(door, &door_arg)) != 0 &&
474 469 retries < VT_DOORCALL_MAX_RETRY)
475 470 if (error == EAGAIN || error == EINTR)
476 471 retries++;
477 472 else
478 473 break;
479 474
480 475 door_ki_rele(door);
481 476
482 477 mutex_enter(&vt_pending_vtno_lock);
483 478 vt_pending_vtno = -1;
484 479 mutex_exit(&vt_pending_vtno_lock);
485 480 }
486 481
487 482 static boolean_t
488 483 vt_validate_hotkeys(int minor)
489 484 {
490 485 /*
491 486 * minor should not succeed the existing minor numbers range.
492 487 */
493 488 if (!vt_minor_valid(minor))
494 489 return (B_FALSE);
495 490
496 491 /*
497 492 * Shouldn't switch to /dev/vt/1 or an unused vt.
498 493 */
499 494 if (!VT_IS_DAEMON(minor) && VT_IS_INUSE(minor))
500 495 return (B_TRUE);
501 496
502 497 return (B_FALSE);
503 498 }
504 499
505 500 static void
506 501 vt_trigger_hotkeys(int vtno)
507 502 {
508 503 mutex_enter(&vt_pending_vtno_lock);
509 504
510 505 if (vt_pending_vtno != -1) {
511 506 mutex_exit(&vt_pending_vtno_lock);
512 507 return;
513 508 }
514 509
515 510 vt_pending_vtno = vtno;
516 511 mutex_exit(&vt_pending_vtno_lock);
517 512 (void) timeout(vt_send_hotkeys, NULL, 1);
518 513 }
519 514
520 515 /*
521 516 * return value:
522 517 * 0: non msg of vt hotkeys
523 518 * 1: msg of vt hotkeys
524 519 */
525 520 int
526 521 vt_check_hotkeys(mblk_t *mp)
527 522 {
528 523 int vtno = 0;
529 524 minor_t minor = 0;
530 525
531 526 /* LINTED E_PTRDIFF_OVERFLOW */
532 527 if (!VT_MSG_SWITCH(mp))
533 528 return (0);
534 529
535 530 switch (VT_MSG_OPCODE(mp)) {
536 531 case 'B':
537 532 /* find out the previous vt */
538 533 if (vc_active_console == VT_MINOR_INVALID)
539 534 return (1);
540 535
541 536 if (VT_IS_DAEMON(vc_active_console)) {
542 537 minor = vt_find_prev(vt_arg2minor(vc_target_console));
543 538 break;
544 539 }
545 540
546 541 minor = vt_find_prev(vc_active_console);
547 542 break;
548 543 case 'F':
549 544 /* find out the next vt */
550 545 if (vc_active_console == VT_MINOR_INVALID)
551 546 return (1);
552 547
553 548 if (VT_IS_DAEMON(vc_active_console)) {
554 549 minor = vt_find_next(vt_arg2minor(vc_target_console));
555 550 break;
556 551 }
557 552
558 553 minor = vt_find_next(vc_active_console);
559 554 break;
560 555 case 'H':
561 556 /* find out the specified vt */
562 557 minor = VT_MSG_VTNO(mp);
563 558
564 559 /* check for system console, Alt + F1 */
565 560 if (minor == 1)
566 561 minor = 0;
567 562 break;
568 563 case 'L':
569 564 /* find out the last vt */
570 565 if ((minor = vc_last_console) == VT_MINOR_INVALID)
571 566 return (1);
572 567 break;
573 568 default:
574 569 return (1);
575 570 }
576 571
577 572 if (!vt_validate_hotkeys(minor))
578 573 return (1);
579 574
580 575 /*
581 576 * for system console, the argument of vtno for
582 577 * vt_activate is 1, though its minor is 0
583 578 */
584 579 if (minor == 0)
585 580 vtno = 1; /* for system console */
586 581 else
587 582 vtno = minor;
588 583
589 584 vt_trigger_hotkeys(vtno);
590 585 return (1);
591 586 }
592 587
593 588 static void
594 589 vt_proc_sendsig(pid_t pid, int sig)
595 590 {
596 591 register proc_t *p;
597 592
598 593 if (pid <= 0)
599 594 return;
600 595
601 596 mutex_enter(&pidlock);
602 597 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
603 598 mutex_exit(&pidlock);
604 599 return;
605 600 }
606 601
607 602 psignal(p, sig);
608 603 mutex_exit(&pidlock);
609 604 }
610 605
611 606 static int
612 607 vt_proc_exists(pid_t pid)
613 608 {
614 609 register proc_t *p;
615 610
616 611 if (pid <= 0)
617 612 return (EINVAL);
618 613
619 614 mutex_enter(&pidlock);
620 615 if ((p = prfind(pid)) == NULL || p->p_stat == SIDL) {
621 616 mutex_exit(&pidlock);
622 617 return (ESRCH);
623 618 }
624 619 mutex_exit(&pidlock);
625 620
626 621 return (0);
627 622 }
628 623
629 624 #define SIG_VALID(x) (((x) > 0) && ((x) <= MAXSIG) && \
630 625 ((x) != SIGKILL) && ((x) != SIGSTOP))
631 626
632 627 static int
633 628 vt_setmode(vc_state_t *pvc, struct vt_mode *pmode)
634 629 {
635 630 if ((pmode->mode != VT_PROCESS) && (pmode->mode != VT_AUTO))
636 631 return (EINVAL);
637 632
638 633 if (!SIG_VALID(pmode->relsig) || !SIG_VALID(pmode->acqsig))
639 634 return (EINVAL);
640 635
641 636 if (pmode->mode == VT_PROCESS) {
642 637 pvc->vc_pid = curproc->p_pid;
643 638 } else {
644 639 pvc->vc_dispnum = 0;
645 640 pvc->vc_login = 0;
646 641 }
647 642
648 643 pvc->vc_switch_mode = pmode->mode;
649 644 pvc->vc_waitv = pmode->waitv;
650 645 pvc->vc_relsig = pmode->relsig;
651 646 pvc->vc_acqsig = pmode->acqsig;
652 647
653 648 return (0);
654 649 }
655 650
656 651 static void
657 652 vt_reset(vc_state_t *pvc)
658 653 {
659 654 pvc->vc_switch_mode = VT_AUTO;
660 655 pvc->vc_pid = -1;
661 656 pvc->vc_dispnum = 0;
662 657 pvc->vc_login = 0;
663 658 pvc->vc_switchto = VT_MINOR_INVALID;
664 659 }
665 660
666 661 /*
667 662 * switch to vt_no from vc_active_console
668 663 */
669 664 static int
670 665 vt_switch(uint_t vt_no, cred_t *credp)
671 666 {
672 667 vc_state_t *pvc_active = vt_minor2vc(vc_active_console);
673 668 vc_state_t *pvc = vt_minor2vc(vt_no);
674 669 minor_t index;
675 670
676 671 ASSERT(pvc_active && pvc);
677 672
678 673 /* sanity test for the target VT and the active VT */
679 674 if (!((pvc->vc_flags & WCS_ISOPEN) && (pvc->vc_flags & WCS_INIT)))
680 675 return (EINVAL);
681 676
682 677 if (!((pvc_active->vc_flags & WCS_ISOPEN) &&
683 678 (pvc_active->vc_flags & WCS_INIT)))
684 679 return (EINVAL);
685 680
686 681 mutex_enter(&vc_lock);
687 682
688 683 tem_switch(pvc_active->vc_tem, pvc->vc_tem, credp);
689 684
690 685 if (!VT_IS_DAEMON(vc_active_console))
691 686 vc_last_console = vc_active_console;
692 687 else
693 688 vc_last_console = vt_arg2minor(vc_target_console);
694 689
695 690 vc_active_console = pvc->vc_minor;
696 691
697 692 if (pvc->vc_switch_mode == VT_PROCESS) {
698 693 pvc->vc_switchto = pvc->vc_minor;
699 694
700 695 /* send it an acquired signal */
701 696 vt_proc_sendsig(pvc->vc_pid, pvc->vc_acqsig);
702 697 }
703 698
704 699 vc_waitactive_reply(vc_active_console, B_FALSE);
705 700
706 701 mutex_exit(&vc_lock);
707 702
708 703 if (!VT_IS_DAEMON(vt_no)) {
709 704 /*
710 705 * Applications that open the virtual console device may request
711 706 * asynchronous notification of VT switching from a previous VT
712 707 * to another one by setting the S_MSG flag in an I_SETSIG
713 708 * STREAMS ioctl. Such processes receive a SIGPOLL signal when
714 709 * a VT switching succeeds.
715 710 */
716 711 for (index = 0; index < VC_INSTANCES_COUNT; index++) {
717 712 vc_state_t *tmp_pvc = vt_minor2vc(index);
718 713 mblk_t *mp;
719 714
720 715 if ((tmp_pvc->vc_flags & WCS_ISOPEN) &&
721 716 (tmp_pvc->vc_flags & WCS_INIT) &&
722 717 (mp = allocb(sizeof (unsigned char), BPRI_HI))) {
723 718 mp->b_datap->db_type = M_PCSIG;
724 719 *mp->b_wptr = SIGPOLL;
725 720 mp->b_wptr += sizeof (unsigned char);
726 721 putnext(RD(tmp_pvc->vc_wq), mp);
727 722 }
728 723 }
729 724 }
730 725
731 726 return (0);
732 727
733 728 }
734 729
735 730 /*
736 731 * vt_no from 0 to n
737 732 *
738 733 * 0 for the vtdaemon sepcial console (only vtdaemon will use it)
739 734 * 1 for the system console (Alt + F1, or Alt + Ctrl + F1),
740 735 * aka Virtual Console #1
741 736 *
742 737 * 2 for Virtual Console #2
743 738 * n for Virtual Console #n
744 739 */
745 740 static minor_t
746 741 vt_arg2minor(uint_t arg)
747 742 {
748 743 if (arg == 0)
749 744 return (1);
750 745
751 746 if (arg == 1)
752 747 return (0);
753 748
754 749 return (arg);
755 750 }
756 751
757 752 static uint_t
758 753 vt_minor2arg(minor_t minor)
759 754 {
760 755 if (minor == 0)
761 756 return (1);
762 757
763 758 if (VT_IS_DAEMON(minor)) {
764 759 /* here it should be the real console */
765 760 return (vc_target_console);
766 761 }
767 762
768 763 return (minor);
769 764 }
770 765
771 766 static int
772 767 vt_activate(uint_t vt_no, cred_t *credp)
773 768 {
774 769 vc_state_t *pvc;
775 770 minor_t minor;
776 771
777 772 minor = vt_arg2minor(vt_no);
778 773 if (!vt_minor_valid(minor))
779 774 return (ENXIO);
780 775 if (minor == vc_active_console) {
781 776 if (VT_IS_DAEMON(minor)) {
782 777 /*
783 778 * vtdaemon is reactivating itself to do locking
784 779 * on behalf of another console, so record current
785 780 * target console as the last console.
786 781 */
787 782 vc_last_console = vt_arg2minor(vc_target_console);
788 783 }
789 784
790 785 return (0);
791 786 }
792 787
793 788 /*
794 789 * In tipline case, the system console is redirected to tipline
795 790 * and thus is always available.
796 791 */
797 792 if (minor == 0 && consconfig_console_is_tipline())
798 793 return (0);
799 794
800 795 if (!VT_IS_INUSE(minor))
801 796 return (ENXIO);
802 797
803 798 pvc = vt_minor2vc(minor);
804 799 if (pvc == NULL)
805 800 return (ENXIO);
806 801 if (pvc->vc_tem == NULL)
807 802 return (ENXIO);
808 803
809 804 pvc = vt_minor2vc(vc_active_console);
810 805 if (pvc == NULL)
811 806 return (ENXIO);
812 807 if (pvc->vc_switch_mode != VT_PROCESS)
813 808 return (vt_switch(minor, credp));
814 809
815 810 /*
816 811 * Validate the process, reset the
817 812 * vt to auto mode if failed.
818 813 */
819 814 if (pvc->vc_pid == -1 || vt_proc_exists(pvc->vc_pid) != 0) {
820 815 /*
821 816 * Xserver has not started up yet,
822 817 * or it dose not exist.
823 818 */
824 819 vt_reset(pvc);
825 820 return (0);
826 821 }
827 822
828 823 /*
829 824 * Send the release signal to the process,
830 825 * and wait VT_RELDISP ioctl from Xserver
831 826 * after its leaving VT.
832 827 */
833 828 vt_proc_sendsig(pvc->vc_pid, pvc->vc_relsig);
834 829 pvc->vc_switchto = minor;
835 830
836 831 /*
837 832 * We don't need a timeout here, for if Xserver refuses
838 833 * or fails to respond to release signal using VT_RELDISP,
839 834 * we cannot successfully switch to our text mode. Actually
840 835 * users can try again. At present we don't support force
841 836 * switch.
842 837 */
843 838 return (0);
844 839 }
845 840
846 841 static int
847 842 vt_reldisp(vc_state_t *pvc, int arg, cred_t *credp)
848 843 {
849 844 minor_t target_vtno = pvc->vc_switchto;
850 845
851 846 if ((pvc->vc_switch_mode != VT_PROCESS) ||
852 847 (pvc->vc_minor != vc_active_console))
853 848 return (EACCES);
854 849
855 850 if (target_vtno == VT_MINOR_INVALID)
856 851 return (EINVAL);
857 852
858 853 pvc->vc_switchto = VT_MINOR_INVALID;
859 854
860 855 if (arg == VT_ACKACQ)
861 856 return (0);
862 857
863 858 if (arg == 0)
864 859 return (0); /* refuse to release */
865 860
866 861 /* Xserver has left VT */
867 862 return (vt_switch(target_vtno, credp));
868 863 }
869 864
870 865 void
871 866 vt_ioctl(queue_t *q, mblk_t *mp)
872 867 {
873 868 vc_state_t *pvc = (vc_state_t *)q->q_ptr;
874 869 struct iocblk *iocp;
875 870 struct vt_mode vtmode;
876 871 struct vt_stat vtinfo;
877 872 struct vt_dispinfo vtdisp;
878 873 mblk_t *tmp;
879 874 int minor;
880 875 int arg;
881 876 int error = 0;
882 877 vc_waitactive_msg_t *wait_msg;
883 878
884 879 iocp = (struct iocblk *)(void *)mp->b_rptr;
885 880 if (consmode != CONS_KFB && iocp->ioc_cmd != VT_ENABLED) {
886 881 vt_iocnak(q, mp, EINVAL);
887 882 return;
888 883 }
889 884
890 885 switch (iocp->ioc_cmd) {
891 886 case VT_ENABLED:
892 887 if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
893 888 error = ENOMEM;
894 889 break;
895 890 }
896 891 *(int *)(void *)tmp->b_rptr = consmode;
897 892 tmp->b_wptr += sizeof (int);
898 893 vt_copyout(q, mp, tmp, sizeof (int));
899 894 return;
900 895
901 896 case KDSETMODE:
902 897 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
903 898 if (arg != KD_TEXT && arg != KD_GRAPHICS) {
904 899 error = EINVAL;
905 900 break;
906 901 }
907 902 if (tem_get_fbmode(pvc->vc_tem) == arg)
908 903 break;
909 904
910 905 tem_set_fbmode(pvc->vc_tem, (uchar_t)arg, iocp->ioc_cr);
911 906
912 907 break;
913 908
914 909 case KDGETMODE:
915 910 if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
916 911 error = ENOMEM;
917 912 break;
918 913 }
919 914 *(int *)(void *)tmp->b_rptr = tem_get_fbmode(pvc->vc_tem);
920 915 tmp->b_wptr += sizeof (int);
921 916 vt_copyout(q, mp, tmp, sizeof (int));
922 917 return;
923 918
924 919 case VT_OPENQRY: /* return number of first free VT */
925 920 if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
926 921 error = ENOMEM;
927 922 break;
928 923 }
929 924
930 925 /* minors of 0 and 1 are not available to end users */
931 926 for (minor = 2; vt_minor_valid(minor); minor++)
932 927 if (!VT_IS_INUSE(minor))
933 928 break;
934 929
935 930 if (!vt_minor_valid(minor))
936 931 minor = -1;
937 932 *(int *)(void *)tmp->b_rptr = minor; /* /dev/vt/minor */
938 933 tmp->b_wptr += sizeof (int);
939 934 vt_copyout(q, mp, tmp, sizeof (int));
940 935 return;
941 936
942 937 case VT_GETMODE:
943 938 vtmode.mode = pvc->vc_switch_mode;
944 939 vtmode.waitv = pvc->vc_waitv;
945 940 vtmode.relsig = pvc->vc_relsig;
946 941 vtmode.acqsig = pvc->vc_acqsig;
947 942 vtmode.frsig = 0;
948 943 if (!(tmp = allocb(sizeof (struct vt_mode), BPRI_MED))) {
949 944 error = ENOMEM;
950 945 break;
951 946 }
952 947 *(struct vt_mode *)(void *)tmp->b_rptr = vtmode;
953 948 tmp->b_wptr += sizeof (struct vt_mode);
954 949 vt_copyout(q, mp, tmp, sizeof (struct vt_mode));
955 950 return;
956 951
957 952 case VT_SETMODE:
958 953 vt_copyin(q, mp, sizeof (struct vt_mode));
959 954 return;
960 955
961 956 case VT_SETDISPINFO:
962 957 /* always enforce sys_devices privilege for setdispinfo */
963 958 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
964 959 break;
965 960
966 961 pvc->vc_dispnum = *(intptr_t *)(void *)mp->b_cont->b_rptr;
967 962 break;
968 963
969 964 case VT_SETDISPLOGIN:
970 965 pvc->vc_login = *(intptr_t *)(void *)mp->b_cont->b_rptr;
971 966 break;
972 967
973 968 case VT_GETDISPINFO:
974 969 vtdisp.v_pid = pvc->vc_pid;
975 970 vtdisp.v_dispnum = pvc->vc_dispnum;
976 971 vtdisp.v_login = pvc->vc_login;
977 972 if (!(tmp = allocb(sizeof (struct vt_dispinfo), BPRI_MED))) {
978 973 error = ENOMEM;
979 974 break;
980 975 }
981 976 *(struct vt_dispinfo *)(void *)tmp->b_rptr = vtdisp;
982 977 tmp->b_wptr += sizeof (struct vt_dispinfo);
983 978 vt_copyout(q, mp, tmp, sizeof (struct vt_dispinfo));
984 979 return;
985 980
986 981 case VT_RELDISP:
987 982 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
988 983 error = vt_reldisp(pvc, arg, iocp->ioc_cr);
989 984 break;
990 985
991 986 case VT_CONFIG:
992 987 /* always enforce sys_devices privilege for config */
993 988 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
994 989 break;
995 990
996 991 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
997 992 error = vt_config(arg);
998 993 break;
999 994
1000 995 case VT_ACTIVATE:
1001 996 /* always enforce sys_devices privilege for secure switch */
1002 997 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
1003 998 break;
1004 999
1005 1000 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
1006 1001 error = vt_activate(arg, iocp->ioc_cr);
1007 1002 break;
1008 1003
1009 1004 case VT_WAITACTIVE:
1010 1005 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
1011 1006 arg = vt_arg2minor(arg);
1012 1007 if (!vt_minor_valid(arg)) {
1013 1008 error = ENXIO;
1014 1009 break;
1015 1010 }
1016 1011 if (arg == vc_active_console)
1017 1012 break;
1018 1013
1019 1014 wait_msg = kmem_zalloc(sizeof (vc_waitactive_msg_t),
1020 1015 KM_NOSLEEP);
1021 1016 if (wait_msg == NULL) {
1022 1017 error = ENXIO;
1023 1018 break;
1024 1019 }
1025 1020
1026 1021 wait_msg->wa_mp = mp;
1027 1022 wait_msg->wa_msg_minor = pvc->vc_minor;
1028 1023 wait_msg->wa_wait_minor = arg;
1029 1024 list_insert_head(&vc_waitactive_list, wait_msg);
1030 1025
1031 1026 return;
1032 1027
1033 1028 case VT_GETSTATE:
1034 1029 /*
1035 1030 * Here v_active is the argument for vt_activate,
1036 1031 * not minor.
1037 1032 */
1038 1033 vtinfo.v_active = vt_minor2arg(vc_active_console);
1039 1034 vtinfo.v_state = 3; /* system console and vtdaemon */
1040 1035
1041 1036 /* we only support 16 vt states since the v_state is short */
1042 1037 for (minor = 2; minor < 16; minor++) {
1043 1038 pvc = vt_minor2vc(minor);
1044 1039 if (pvc == NULL)
1045 1040 break;
1046 1041 if (VT_IS_INUSE(minor))
1047 1042 vtinfo.v_state |= (1 << pvc->vc_minor);
1048 1043 }
1049 1044
1050 1045 if (!(tmp = allocb(sizeof (struct vt_stat), BPRI_MED))) {
1051 1046 error = ENOMEM;
1052 1047 break;
1053 1048 }
1054 1049 *(struct vt_stat *)(void *)tmp->b_rptr = vtinfo;
1055 1050 tmp->b_wptr += sizeof (struct vt_stat);
1056 1051 vt_copyout(q, mp, tmp, sizeof (struct vt_stat));
1057 1052 return;
1058 1053
1059 1054 case VT_SET_TARGET:
1060 1055 /* always enforce sys_devices privilege */
1061 1056 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
1062 1057 break;
1063 1058
1064 1059 arg = *(intptr_t *)(void *)mp->b_cont->b_rptr;
1065 1060
1066 1061 /* vtdaemon is doing authentication for this target console */
1067 1062 vc_target_console = arg;
1068 1063 break;
1069 1064
1070 1065 case VT_GETACTIVE: /* get real active console (minor) */
1071 1066 if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
1072 1067 error = ENOMEM;
1073 1068 break;
1074 1069 }
1075 1070 *(int *)(void *)tmp->b_rptr = vc_active_console;
1076 1071 tmp->b_wptr += sizeof (int);
1077 1072 vt_copyout(q, mp, tmp, sizeof (int));
1078 1073 return;
1079 1074
1080 1075 case VT_GET_CONSUSER:
1081 1076 if (!(tmp = allocb(sizeof (int), BPRI_MED))) {
1082 1077 error = ENOMEM;
1083 1078 break;
1084 1079 }
1085 1080
1086 1081 if (vc_cons_user == VT_MINOR_INVALID) {
1087 1082 /*
1088 1083 * Return -1 if console user link points to
1089 1084 * /dev/console
1090 1085 */
1091 1086 *(int *)(void *)tmp->b_rptr = -1;
1092 1087 } else {
1093 1088 *(int *)(void *)tmp->b_rptr = vc_cons_user;
1094 1089 }
1095 1090
1096 1091 tmp->b_wptr += sizeof (int);
1097 1092 vt_copyout(q, mp, tmp, sizeof (int));
1098 1093 return;
1099 1094
1100 1095 case VT_RESET_CONSUSER:
1101 1096 /* always enforce sys_devices privilege */
1102 1097 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
1103 1098 break;
1104 1099
1105 1100 /* Ensure it comes from /dev/console */
1106 1101 if (pvc->vc_minor != 0) {
1107 1102 error = ENXIO;
1108 1103 break;
1109 1104 }
1110 1105
1111 1106 mutex_enter(&vc_lock);
1112 1107 vc_cons_user = VT_MINOR_INVALID;
1113 1108 mutex_exit(&vc_lock);
1114 1109 break;
1115 1110
1116 1111 case VT_SET_CONSUSER:
1117 1112 /* always enforce sys_devices privilege */
1118 1113 if ((error = secpolicy_console(iocp->ioc_cr)) != 0)
1119 1114 break;
1120 1115
1121 1116 mutex_enter(&vc_lock);
1122 1117 vc_cons_user = pvc->vc_minor;
1123 1118 mutex_exit(&vc_lock);
1124 1119 break;
1125 1120
1126 1121 default:
1127 1122 error = ENXIO;
1128 1123 break;
1129 1124 }
1130 1125
1131 1126 if (error != 0)
1132 1127 vt_iocnak(q, mp, error);
1133 1128 else
1134 1129 vt_iocack(q, mp);
1135 1130 }
1136 1131
1137 1132 void
1138 1133 vt_miocdata(queue_t *qp, mblk_t *mp)
1139 1134 {
1140 1135 vc_state_t *pvc = (vc_state_t *)qp->q_ptr;
1141 1136 struct copyresp *copyresp;
1142 1137 struct vt_mode *pmode;
1143 1138 int error = 0;
1144 1139
1145 1140 copyresp = (struct copyresp *)(void *)mp->b_rptr;
1146 1141 if (copyresp->cp_rval) {
1147 1142 vt_iocnak(qp, mp, EAGAIN);
1148 1143 return;
1149 1144 }
1150 1145
1151 1146 switch (copyresp->cp_cmd) {
1152 1147 case VT_SETMODE:
1153 1148 pmode = (struct vt_mode *)(void *)mp->b_cont->b_rptr;
1154 1149 error = vt_setmode(pvc, pmode);
1155 1150 break;
1156 1151
1157 1152 case KDGETMODE:
1158 1153 case VT_OPENQRY:
1159 1154 case VT_GETMODE:
1160 1155 case VT_GETDISPINFO:
1161 1156 case VT_GETSTATE:
1162 1157 case VT_ENABLED:
1163 1158 case VT_GETACTIVE:
1164 1159 break;
1165 1160
1166 1161 default:
1167 1162 error = ENXIO;
1168 1163 break;
1169 1164 }
1170 1165
1171 1166 if (error != 0)
1172 1167 vt_iocnak(qp, mp, error);
1173 1168 else
1174 1169 vt_iocack(qp, mp);
1175 1170 }
1176 1171
1177 1172 static void
1178 1173 vt_iocack(queue_t *qp, mblk_t *mp)
1179 1174 {
1180 1175 struct iocblk *iocbp = (struct iocblk *)(void *)mp->b_rptr;
1181 1176
1182 1177 mp->b_datap->db_type = M_IOCACK;
1183 1178 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
1184 1179 iocbp->ioc_error = 0;
1185 1180 iocbp->ioc_count = 0;
1186 1181 iocbp->ioc_rval = 0;
1187 1182 if (mp->b_cont != NULL) {
1188 1183 freemsg(mp->b_cont);
1189 1184 mp->b_cont = NULL;
1190 1185 }
1191 1186 qreply(qp, mp);
1192 1187 }
1193 1188
1194 1189 static void
1195 1190 vt_iocnak(queue_t *qp, mblk_t *mp, int error)
1196 1191 {
1197 1192 struct iocblk *iocp = (struct iocblk *)(void *)mp->b_rptr;
1198 1193
1199 1194 mp->b_datap->db_type = M_IOCNAK;
1200 1195 iocp->ioc_rval = 0;
1201 1196 iocp->ioc_count = 0;
1202 1197 iocp->ioc_error = error;
1203 1198 if (mp->b_cont != NULL) {
1204 1199 freemsg(mp->b_cont);
1205 1200 mp->b_cont = NULL;
1206 1201 }
1207 1202 qreply(qp, mp);
1208 1203 }
1209 1204
1210 1205 static void
1211 1206 vt_copyin(queue_t *qp, mblk_t *mp, uint_t size)
1212 1207 {
1213 1208 struct copyreq *cqp;
1214 1209
1215 1210 cqp = (struct copyreq *)(void *)mp->b_rptr;
1216 1211 cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr);
1217 1212 cqp->cq_size = size;
1218 1213 cqp->cq_flag = 0;
1219 1214 cqp->cq_private = (mblk_t *)NULL;
1220 1215 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
1221 1216 mp->b_datap->db_type = M_COPYIN;
1222 1217 if (mp->b_cont)
1223 1218 freemsg(mp->b_cont);
1224 1219 mp->b_cont = (mblk_t *)NULL;
1225 1220 qreply(qp, mp);
1226 1221 }
1227 1222
1228 1223 static void
1229 1224 vt_copyout(queue_t *qp, mblk_t *mp, mblk_t *tmp, uint_t size)
1230 1225 {
1231 1226 struct copyreq *cqp;
1232 1227
1233 1228 cqp = (struct copyreq *)(void *)mp->b_rptr;
1234 1229 cqp->cq_size = size;
1235 1230 cqp->cq_addr = *((caddr_t *)(void *)mp->b_cont->b_rptr);
1236 1231 cqp->cq_flag = 0;
1237 1232 cqp->cq_private = (mblk_t *)NULL;
1238 1233 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
1239 1234 mp->b_datap->db_type = M_COPYOUT;
1240 1235 if (mp->b_cont)
1241 1236 freemsg(mp->b_cont);
1242 1237 mp->b_cont = tmp;
1243 1238 qreply(qp, mp);
1244 1239 }
1245 1240
1246 1241 /*
1247 1242 * Get vc state from minor.
1248 1243 * Once a caller gets a vc_state_t from this function,
1249 1244 * the vc_state_t is guaranteed not being freed before
1250 1245 * the caller leaves this STREAMS module by the D_MTPERMOD
1251 1246 * perimeter.
1252 1247 */
1253 1248 vc_state_t *
1254 1249 vt_minor2vc(minor_t minor)
1255 1250 {
1256 1251 avl_index_t where;
1257 1252 vc_state_t target;
1258 1253
1259 1254 if (minor != VT_ACTIVE) {
1260 1255 target.vc_minor = minor;
1261 1256 return (avl_find(&vc_avl_root, &target, &where));
1262 1257 }
1263 1258
1264 1259 if (vc_active_console == VT_MINOR_INVALID)
1265 1260 target.vc_minor = 0;
1266 1261 else
1267 1262 target.vc_minor = vc_active_console;
1268 1263
1269 1264 return (avl_find(&vc_avl_root, &target, &where));
1270 1265 }
1271 1266
1272 1267 static void
1273 1268 vt_state_init(vc_state_t *vcptr, minor_t minor)
1274 1269 {
1275 1270 mutex_init(&vcptr->vc_state_lock, NULL, MUTEX_DRIVER, NULL);
1276 1271
1277 1272 mutex_enter(&vcptr->vc_state_lock);
1278 1273 vcptr->vc_flags = 0;
1279 1274 mutex_exit(&vcptr->vc_state_lock);
1280 1275
1281 1276 vcptr->vc_pid = -1;
1282 1277 vcptr->vc_dispnum = 0;
1283 1278 vcptr->vc_login = 0;
1284 1279 vcptr->vc_switchto = VT_MINOR_INVALID;
1285 1280 vcptr->vc_switch_mode = VT_AUTO;
1286 1281 vcptr->vc_relsig = SIGUSR1;
1287 1282 vcptr->vc_acqsig = SIGUSR1;
1288 1283 vcptr->vc_tem = NULL;
1289 1284 vcptr->vc_bufcallid = 0;
1290 1285 vcptr->vc_timeoutid = 0;
1291 1286 vcptr->vc_wq = NULL;
1292 1287 vcptr->vc_minor = minor;
1293 1288 }
1294 1289
1295 1290 void
1296 1291 vt_resize(uint_t count)
1297 1292 {
1298 1293 uint_t vc_num, i;
1299 1294
1300 1295 ASSERT(MUTEX_HELD(&vc_lock));
1301 1296
1302 1297 vc_num = VC_INSTANCES_COUNT;
1303 1298
1304 1299 if (count == vc_num)
1305 1300 return;
1306 1301
1307 1302 if (count > vc_num) {
1308 1303 for (i = vc_num; i < count; i++) {
1309 1304 vc_state_t *vcptr = kmem_zalloc(sizeof (vc_state_t),
1310 1305 KM_SLEEP);
1311 1306 vt_state_init(vcptr, i);
1312 1307 avl_add(&vc_avl_root, vcptr);
1313 1308 }
1314 1309 return;
1315 1310 }
1316 1311
1317 1312 for (i = vc_num; i > count; i--) {
1318 1313 avl_index_t where;
1319 1314 vc_state_t target, *found;
1320 1315
1321 1316 target.vc_minor = i - 1;
1322 1317 found = avl_find(&vc_avl_root, &target, &where);
1323 1318 ASSERT(found != NULL && found->vc_flags == 0);
1324 1319 avl_remove(&vc_avl_root, found);
1325 1320 kmem_free(found, sizeof (vc_state_t));
1326 1321 }
1327 1322 }
1328 1323
1329 1324 static int
1330 1325 vc_avl_compare(const void *first, const void *second)
1331 1326 {
1332 1327 const vc_state_t *vcptr1 = first;
1333 1328 const vc_state_t *vcptr2 = second;
1334 1329
1335 1330 if (vcptr1->vc_minor < vcptr2->vc_minor)
1336 1331 return (-1);
1337 1332
1338 1333 if (vcptr1->vc_minor == vcptr2->vc_minor)
1339 1334 return (0);
↓ open down ↓ |
1206 lines elided |
↑ open up ↑ |
1340 1335
1341 1336 return (1);
1342 1337 }
1343 1338
1344 1339 /*
1345 1340 * Only called from wc init().
1346 1341 */
1347 1342 void
1348 1343 vt_init(void)
1349 1344 {
1350 -#ifdef __lock_lint
1351 - ASSERT(NO_COMPETING_THREADS);
1352 -#endif
1353 -
1354 1345 avl_create(&vc_avl_root, vc_avl_compare, sizeof (vc_state_t),
1355 1346 offsetof(vc_state_t, vc_avl_node));
1356 1347
1357 1348 list_create(&vc_waitactive_list, sizeof (vc_waitactive_msg_t),
1358 1349 offsetof(vc_waitactive_msg_t, wa_list_node));
1359 1350
1360 1351 mutex_init(&vc_lock, NULL, MUTEX_DRIVER, NULL);
1361 1352 mutex_init(&vt_pending_vtno_lock, NULL, MUTEX_DRIVER, NULL);
1362 1353 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX