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
vt_init_ttycommon(tty_common_t * pcommon)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
vt_config(uint_t count)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
vt_clean(queue_t * q,vc_state_t * pvc)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
vc_waitactive_reply(int minor,boolean_t close)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
vt_close(queue_t * q,vc_state_t * pvc,cred_t * credp)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
vt_init_tty(vc_state_t * pvc)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
vt_open(minor_t minor,queue_t * rq,cred_t * crp)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
vt_find_prev(minor_t cur)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
vt_find_next(minor_t cur)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
vt_send_hotkeys(void * timeout_arg)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
vt_validate_hotkeys(int minor)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
vt_trigger_hotkeys(int vtno)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
vt_check_hotkeys(mblk_t * mp)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
vt_proc_sendsig(pid_t pid,int sig)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
vt_proc_exists(pid_t pid)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
vt_setmode(vc_state_t * pvc,struct vt_mode * pmode)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
vt_reset(vc_state_t * pvc)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
vt_switch(uint_t vt_no,cred_t * credp)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
vt_arg2minor(uint_t arg)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
vt_minor2arg(minor_t minor)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
vt_activate(uint_t vt_no,cred_t * credp)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
vt_reldisp(vc_state_t * pvc,int arg,cred_t * credp)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
vt_ioctl(queue_t * q,mblk_t * mp)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
vt_miocdata(queue_t * qp,mblk_t * mp)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
vt_iocack(queue_t * qp,mblk_t * mp)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
vt_iocnak(queue_t * qp,mblk_t * mp,int error)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
vt_copyin(queue_t * qp,mblk_t * mp,uint_t size)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
vt_copyout(queue_t * qp,mblk_t * mp,mblk_t * tmp,uint_t size)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 *
vt_minor2vc(minor_t minor)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
vt_state_init(vc_state_t * vcptr,minor_t minor)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
vt_resize(uint_t count)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
vc_avl_compare(const void * first,const void * second)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
vt_init(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