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 }