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