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