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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Vntsd handles two types of special commands, one is telnet
28 * commands and another is vntsd special commands.
29 * telnet commands supported are:
42 * Vntsd special commands are:
44 * Send alternate break (~^B)
46 * Force write access (~w)
48 * Console previous (~p)
56 #include <sys/types.h>
57 #include <sys/socket.h>
58 #include <netinet/in.h>
61 #include <sys/termio.h>
67 char vntsd_eol
[] = { CR
, LF
, 0};
69 typedef int (*e_func_t
)(vntsd_client_t
*clientp
);
70 /* structure for daemon special cmd */
72 char e_char
; /* char to match on */
73 char *e_help
; /* help string */
74 e_func_t e_func
; /* command */
77 /* genbrk() - send a break to vcc driver */
79 genbrk(vntsd_client_t
*clientp
)
85 assert(clientp
->cons
);
87 consp
= clientp
->cons
;
88 D1(stderr
, "t@%d genbrk fd=%d sockfd %d\n", thr_self(),
89 consp
->vcc_fd
, clientp
->sockfd
);
91 assert(consp
->clientpq
!= NULL
);
92 if (consp
->clientpq
->handle
!= clientp
) {
94 return (vntsd_write_line(clientp
,
95 gettext(VNTSD_NO_WRITE_ACCESS_MSG
)));
99 if (ioctl(consp
->vcc_fd
, TCSBRK
, NULL
)) {
100 return (VNTSD_ERR_VCC_IOCTL
);
103 return (VNTSD_STATUS_CONTINUE
);
107 /* genaltbrk() - handle the alternate break sequence */
109 genaltbrk(vntsd_client_t
*clientp
)
112 char brkseq
[2] = { '~', CNTRL('B')};
115 assert(clientp
->cons
);
117 consp
= clientp
->cons
;
118 D1(stderr
, "t@%d genaltbrk fd=%d sockfd %d\n", thr_self(),
119 consp
->vcc_fd
, clientp
->sockfd
);
121 assert(consp
->clientpq
!= NULL
);
122 if (consp
->clientpq
->handle
!= clientp
) {
124 return (vntsd_write_line(clientp
,
125 gettext(VNTSD_NO_WRITE_ACCESS_MSG
)));
129 * Unlike the genbrk() function we will just forward the break sequence
130 * on to vcc and subsequently the underlying console driver. This will
131 * involve sending the characters '~' and CNTRL('B').
133 if ((vntsd_write_fd(clientp
->cons
->vcc_fd
, brkseq
, sizeof (brkseq
))) ==
135 return (VNTSD_STATUS_CONTINUE
);
137 return (VNTSD_STATUS_VCC_IO_ERR
);
141 * console_forward() - cycle client to the next console
142 * in the group queue.
145 console_forward(vntsd_client_t
*clientp
)
147 /* forward when there are mutiple consoles in the group */
148 if (clientp
->cons
->group
->num_cons
> 1)
149 return (VNTSD_STATUS_MOV_CONS_FORWARD
);
151 return (VNTSD_STATUS_CONTINUE
);
156 * console_backward() - cycle client to the previous
157 * console in the group queue.
160 console_backward(vntsd_client_t
*clientp
)
162 /* backward when there are mutiple consoles in the group */
163 if (clientp
->cons
->group
->num_cons
> 1)
164 return (VNTSD_STATUS_MOV_CONS_BACKWARD
);
166 return (VNTSD_STATUS_CONTINUE
);
170 /* acquire_write() - acquire write access to a console. */
172 acquire_write(vntsd_client_t
*clientp
)
179 consp
= clientp
->cons
;
182 if (consp
->clientpq
->handle
== clientp
) {
183 /* client is a writer */
184 if ((rv
= vntsd_write_line(clientp
,
185 gettext("You have write permission"))) !=
190 return (VNTSD_STATUS_CONTINUE
);
193 /* message to client */
194 if ((rv
= vntsd_write_client(clientp
, vntsd_eol
, VNTSD_EOL_LEN
))
201 * The following string should be formatted to fit on multiple lines
202 * assuming a line width of at most 78 characters. There must be no
205 if ((rv
= vntsd_write_lines(clientp
,
206 gettext("Warning: another user currently "
207 "has write permission\nto this console and forcibly removing "
208 "him/her will terminate\nany current write action and all work "
209 "will be lost."))) != VNTSD_SUCCESS
) {
213 /* get client yes no */
214 if ((rv
= vntsd_write_client(clientp
, vntsd_eol
,
215 VNTSD_EOL_LEN
)) != VNTSD_SUCCESS
) {
219 if ((rv
= vntsd_get_yes_no(clientp
,
220 gettext("Would you like to continue?"),
221 &yes_no
)) != VNTSD_SUCCESS
) {
225 if (yes_no
== B_FALSE
) {
226 /* client change mind no need to acquire write access */
227 return (VNTSD_STATUS_CONTINUE
);
230 return (VNTSD_STATUS_ACQUIRE_WRITER
);
233 /* client_exit() - disconnect client from the console. */
237 return (VNTSD_STATUS_RESELECT_CONS
);
240 static int daemon_cmd_help(vntsd_client_t
*clientp
);
242 /* table for daemon commands */
244 static esctable_t etable
[] = {
246 /* send a break to vcc */
247 {'#', "Send break", genbrk
},
249 /* alternate break sequence */
250 {CNTRL('B'), "Send alternate break", genaltbrk
},
253 {'.', "Exit from this console", (e_func_t
)client_exit
},
255 /* acquire write access */
256 {'w', "Force write access", acquire_write
},
258 /* connect to next console in queue */
259 {'n', "Console next", (e_func_t
)console_forward
},
261 /* connect to previous console in queue */
262 {'p', "Console previous", (e_func_t
)console_backward
},
264 /* help must be next to last */
265 {'?', "Help", daemon_cmd_help
},
267 /* table terminator */
272 vntsd_init_esctable_msgs(void)
276 for (p
= etable
; p
->e_char
!= '\0'; p
++) {
277 p
->e_help
= gettext(p
->e_help
);
281 /* daemon_cmd_help() - print help. */
283 daemon_cmd_help(vntsd_client_t
*clientp
)
287 char buf
[VNTSD_LINE_LEN
];
289 if ((rv
= vntsd_write_client(clientp
, vntsd_eol
,
290 VNTSD_EOL_LEN
)) != VNTSD_SUCCESS
) {
296 * VNTSD is the name of the VNTS daemon and should not be translated.
298 if ((rv
= vntsd_write_line(clientp
, gettext("VNTSD commands"))) !=
303 for (p
= etable
; p
->e_char
; p
++) {
305 if (p
->e_char
== CNTRL('B')) {
306 (void) snprintf(buf
, sizeof (buf
), "~^B --%s",
309 (void) snprintf(buf
, sizeof (buf
),
310 "~%c --%s", p
->e_char
, p
->e_help
);
313 if ((rv
= vntsd_write_line(clientp
, buf
)) != VNTSD_SUCCESS
) {
318 return (VNTSD_STATUS_CONTINUE
);
321 /* exit from daemon command */
323 exit_daemon_cmd(vntsd_client_t
*clientp
, int rv
)
325 (void) mutex_lock(&clientp
->lock
);
326 clientp
->status
&= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD
;
327 (void) mutex_unlock(&clientp
->lock
);
332 * vntsd_process_daemon_cmd() - special commands
333 * "<RET>~" vntsd daemon commands
334 * "<RET>~~" enter '~' character
337 vntsd_process_daemon_cmd(vntsd_client_t
*clientp
, char c
)
343 prev_char
= clientp
->prev_char
;
345 if (c
!= VNTSD_DAEMON_CMD
|| (prev_char
!= 0 && prev_char
!= CR
)) {
346 /* not a daemon command */
347 return (VNTSD_SUCCESS
);
350 if (clientp
->status
& VNTSD_CLIENT_DISABLE_DAEMON_CMD
) {
351 return (VNTSD_STATUS_CONTINUE
);
354 /* no reentry to process_daemon_cmd */
355 (void) mutex_lock(&clientp
->lock
);
356 clientp
->status
|= VNTSD_CLIENT_DISABLE_DAEMON_CMD
;
357 (void) mutex_unlock(&clientp
->lock
);
359 D3(stderr
, "t@%d process_daemon_cmd %d %d \n", thr_self(),
360 clientp
->cons
->vcc_fd
, clientp
->sockfd
);
362 /* read in command */
363 if ((rv
= vntsd_read_char(clientp
, &c
)) != VNTSD_SUCCESS
) {
364 return (exit_daemon_cmd(clientp
, rv
));
367 if (c
== VNTSD_DAEMON_CMD
) {
369 * received another '~'
370 * a user types '~~' to get '~'
372 (void) mutex_lock(&clientp
->lock
);
373 clientp
->status
&= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD
;
374 (void) mutex_unlock(&clientp
->lock
);
375 return (VNTSD_SUCCESS
);
378 for (p
= etable
; p
->e_char
; p
++) {
379 if (p
->e_char
== c
) {
382 rv
= (*p
->e_func
)(clientp
);
383 return (exit_daemon_cmd(clientp
, rv
));
387 /* no match, print out the help */
389 assert(p
->e_char
== '?');
390 rv
= (*p
->e_func
)(clientp
);
392 return (exit_daemon_cmd(clientp
, rv
));
396 /* vntsd_set_telnet_options() - change telnet client to character mode. */
398 vntsd_set_telnet_options(int fd
)
400 /* set client telnet options */
401 uint8_t buf
[] = {IAC
, DONT
, LINEMODE
, IAC
, WILL
, SUPRESS
, IAC
, WILL
,
402 TEL_ECHO
, IAC
, DONT
, TERM_TYPE
, IAC
, DONT
, TERM_SP
,
403 IAC
, DONT
, STATUS
, IAC
, DONT
, FC
, IAC
, DONT
, TM
, IAC
, DONT
, ENV
,
404 IAC
, DONT
, WIN_SIZE
};
406 return (vntsd_write_fd(fd
, (char *)buf
, 30));
409 /* vntsd_telnet_cmd() process telnet commands */
411 vntsd_telnet_cmd(vntsd_client_t
*clientp
, char c
)
415 int rv
= VNTSD_STATUS_CONTINUE
;
419 if ((uint8_t)c
!= IAC
) {
421 return (VNTSD_SUCCESS
);
424 if ((rv
= vntsd_read_char(clientp
, &cmd
)) != VNTSD_SUCCESS
) {
428 if ((uint8_t)cmd
== WILL
|| (uint8_t)cmd
== WONT
||
429 (uint8_t)cmd
== DO
|| (uint8_t)cmd
== DONT
) {
430 if ((rv
= vntsd_read_char(clientp
, &c
)) != VNTSD_SUCCESS
) {
436 switch ((uint8_t)cmd
) {
440 switch ((uint8_t)c
) {
446 syslog(LOG_ERR
, "not support telnet WILL %x\n", c
);
453 switch ((uint8_t)c
) {
458 syslog(LOG_ERR
, "not support telnet WONT %x\n", c
);
469 rv
= vntsd_write_client(clientp
, (char *)buf
, 3);
475 /* send break to vcc */
476 rv
= genbrk(clientp
);
484 static char aytresp
[] = "vntsd here";
486 rv
= vntsd_write_client(clientp
, aytresp
,
487 sizeof (aytresp
) - 1);
493 return (VNTSD_STATUS_CONTINUE
);
496 syslog(LOG_ERR
, "not support telnet ctrl %2.2x\n", 0xff & cmd
);
500 if (rv
== VNTSD_SUCCESS
) {
501 return (VNTSD_STATUS_CONTINUE
);
509 * vntsd_ctrl_cmd() - control keys
510 * read and write suspend are supported.
513 vntsd_ctrl_cmd(vntsd_client_t
*clientp
, char c
)
517 D3(stderr
, "t@%d vntsd_ctrl_cmd%d %d\n", thr_self(),
518 clientp
->cons
->vcc_fd
, clientp
->sockfd
);
520 if ((c
!= START
) && (c
!= STOP
)) {
521 /* not a supported control command */
522 return (VNTSD_SUCCESS
);
526 D3(stderr
, "t@%d client restart\n", thr_self());
528 /* send resume read */
531 if (ioctl(clientp
->cons
->vcc_fd
, TCXONC
, &cmd
)) {
532 return (VNTSD_STATUS_VCC_IO_ERR
);
538 D3(stderr
, "t@%d client suspend\n", thr_self());
540 /* send suspend read */
543 if (ioctl(clientp
->cons
->vcc_fd
, TCXONC
, &cmd
)) {
544 return (VNTSD_STATUS_VCC_IO_ERR
);
549 return (VNTSD_STATUS_CONTINUE
);