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.
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.
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]
21 #pragma ident "%Z%%M% %I% %E% SMI"
24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
29 * read thread - Read from tcp client and write to vcc driver. There are one
30 * writer and multiple readers per console. The first client who connects to
31 * a console get write access. An error message is returned to readers if they
32 * attemp to input commands. Read thread accepts special daemon commands from
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <netinet/in.h>
53 /* write_vcc() - write to vcc virtual console */
55 write_vcc(vntsd_client_t
*clientp
, char c
)
61 assert(clientp
->cons
);
63 n
= write(clientp
->cons
->vcc_fd
, &c
, 1);
68 return (vntsd_cons_chk_intr(clientp
));
71 return (VNTSD_STATUS_VCC_IO_ERR
);
75 return (VNTSD_SUCCESS
);
80 * acquire_writer() the client is going to be writer.
81 * insert the client to the head of the console client queue.
84 acquire_writer(vntsd_client_t
*clientp
)
87 vntsd_client_t
*writerp
;
90 D1(stderr
, "t@%d:acuire_writer :client@%d\n", thr_self(),
93 assert(clientp
!= NULL
);
94 consp
= clientp
->cons
;
98 (void) mutex_lock(&consp
->lock
);
100 assert(consp
->clientpq
!= NULL
);
101 if (consp
->clientpq
->handle
== clientp
) {
102 /* clientp is a writer already */
103 (void) mutex_unlock(&consp
->lock
);
104 return (VNTSD_SUCCESS
);
108 writerp
= (vntsd_client_t
*)(consp
->clientpq
->handle
);
110 (void) mutex_lock(&writerp
->lock
);
112 rv
= vntsd_que_rm(&(consp
->clientpq
), clientp
);
113 assert(rv
== VNTSD_SUCCESS
);
115 (void) mutex_lock(&clientp
->lock
);
117 /* move client to be first in the console queue */
118 consp
->clientpq
->handle
= clientp
;
120 /* move previous writer to be the second in the queue */
121 rv
= vntsd_que_insert_after(consp
->clientpq
, clientp
, writerp
);
123 (void) mutex_unlock(&consp
->lock
);
124 (void) mutex_unlock(&writerp
->lock
);
125 (void) mutex_unlock(&clientp
->lock
);
127 if (rv
!= VNTSD_SUCCESS
) {
131 /* write warning message to the writer */
133 if ((rv
= vntsd_write_line(writerp
,
134 gettext("Warning: Console connection forced into read-only mode")))
139 return (VNTSD_SUCCESS
);
142 /* interrupt handler */
144 vntsd_cons_chk_intr(vntsd_client_t
*clientp
)
147 if (clientp
->status
& VNTSD_CLIENT_TIMEOUT
) {
148 return (VNTSD_STATUS_CLIENT_QUIT
);
150 if (clientp
->status
& VNTSD_CLIENT_CONS_DELETED
) {
151 return (VNTSD_STATUS_RESELECT_CONS
);
154 if (clientp
->status
& VNTSD_CLIENT_IO_ERR
) {
155 return (VNTSD_STATUS_CLIENT_QUIT
);
157 return (VNTSD_STATUS_CONTINUE
);
160 /* read from client */
162 read_char(vntsd_client_t
*clientp
, char *c
)
168 rv
= vntsd_read_data(clientp
, c
);
172 case VNTSD_STATUS_ACQUIRE_WRITER
:
173 clientp
->prev_char
= 0;
174 rv
= acquire_writer(clientp
);
175 if (rv
!= VNTSD_SUCCESS
) {
182 * Based on telnet protocol, when an <eol> is entered,
183 * vntsd receives <0x0d,0x00>. However, console expects
184 * <0xd> only. We need to filter out <0x00>.
186 if (clientp
->prev_char
== 0xd && *c
== 0) {
187 clientp
->prev_char
= *c
;
191 clientp
->prev_char
= *c
;
195 assert(rv
!= VNTSD_STATUS_CONTINUE
);
196 clientp
->prev_char
= 0;
203 /* vntsd_read worker */
205 vntsd_read(vntsd_client_t
*clientp
)
212 D3(stderr
, "t@%d vntsd_read@%d\n", thr_self(), clientp
->sockfd
);
217 rv
= read_char(clientp
, &c
);
219 if (rv
== VNTSD_STATUS_INTR
) {
220 rv
= vntsd_cons_chk_intr(clientp
);
223 if (rv
!= VNTSD_SUCCESS
) {
227 assert(clientp
->cons
);
230 * Only keyboard inputs from first connection to a
231 * guest console should be accepted. Check to see if
232 * this client is the first connection in console
235 if (clientp
->cons
->clientpq
->handle
!= clientp
) {
237 * Since this console connection is not the first
238 * connection in the console queue,
239 * it is operating in 'reader'
240 * mode, print warning and ignore the input.
242 rv
= vntsd_write_line(clientp
,
243 gettext(VNTSD_NO_WRITE_ACCESS_MSG
));
245 /* check errors and interrupts */
246 if (rv
== VNTSD_STATUS_INTR
) {
247 rv
= vntsd_cons_chk_intr(clientp
);
250 if (rv
!= VNTSD_SUCCESS
) {
257 rv
= vntsd_ctrl_cmd(clientp
, c
);
260 case VNTSD_STATUS_CONTINUE
:
263 case VNTSD_STATUS_INTR
:
264 rv
= vntsd_cons_chk_intr(clientp
);
265 if (rv
!= VNTSD_SUCCESS
) {
276 rv
= write_vcc(clientp
, c
);
277 if (rv
== VNTSD_STATUS_INTR
) {
278 rv
= vntsd_cons_chk_intr(clientp
);
280 if (rv
!= VNTSD_SUCCESS
) {