11ae08745Sheppo /* 21ae08745Sheppo * CDDL HEADER START 31ae08745Sheppo * 41ae08745Sheppo * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 71ae08745Sheppo * 81ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 101ae08745Sheppo * See the License for the specific language governing permissions 111ae08745Sheppo * and limitations under the License. 121ae08745Sheppo * 131ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 161ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181ae08745Sheppo * 191ae08745Sheppo * CDDL HEADER END 201ae08745Sheppo */ 211ae08745Sheppo /* 221ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231ae08745Sheppo * Use is subject to license terms. 241ae08745Sheppo */ 251ae08745Sheppo 261ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 271ae08745Sheppo 281ae08745Sheppo /* 291ae08745Sheppo * Vntsd handles two types of special commands, one is telnet 301ae08745Sheppo * commands and another is vntsd special commands. 311ae08745Sheppo * telnet commands supported are: 321ae08745Sheppo * WILL 331ae08745Sheppo * WONT 341ae08745Sheppo * DO 351ae08745Sheppo * DONT 361ae08745Sheppo * TEL_ECHO 371ae08745Sheppo * SUPRESS 381ae08745Sheppo * LINEMODE 391ae08745Sheppo * BRK 401ae08745Sheppo * AYT 411ae08745Sheppo * HT 421ae08745Sheppo * 431ae08745Sheppo * Vntsd special commands are: 448e6a2a04Slm66018 * Send break (~#) 458e6a2a04Slm66018 * Exit (~.) 468e6a2a04Slm66018 * Force write access (~w) 478e6a2a04Slm66018 * Console next (~n) 488e6a2a04Slm66018 * Console previous (~p) 498e6a2a04Slm66018 * Help (~?) 501ae08745Sheppo */ 511ae08745Sheppo 521ae08745Sheppo #include <stdio.h> 531ae08745Sheppo #include <stdlib.h> 541ae08745Sheppo #include <string.h> 551ae08745Sheppo #include <unistd.h> 561ae08745Sheppo #include <sys/types.h> 571ae08745Sheppo #include <sys/socket.h> 581ae08745Sheppo #include <netinet/in.h> 591ae08745Sheppo #include <thread.h> 601ae08745Sheppo #include <ctype.h> 611ae08745Sheppo #include <sys/termio.h> 621ae08745Sheppo #include <libintl.h> 631ae08745Sheppo #include <syslog.h> 641ae08745Sheppo #include "vntsd.h" 651ae08745Sheppo #include "chars.h" 661ae08745Sheppo 671ae08745Sheppo char vntsd_eol[] = { CR, LF, 0}; 681ae08745Sheppo 691ae08745Sheppo typedef int (*e_func_t)(vntsd_client_t *clientp); 701ae08745Sheppo /* structure for daemon special cmd */ 711ae08745Sheppo typedef struct { 721ae08745Sheppo char e_char; /* char to match on */ 731ae08745Sheppo char *e_help; /* help string */ 741ae08745Sheppo e_func_t e_func; /* command */ 751ae08745Sheppo } esctable_t; 761ae08745Sheppo 771ae08745Sheppo /* genbrk() - send a break to vcc driver */ 781ae08745Sheppo static int 791ae08745Sheppo genbrk(vntsd_client_t *clientp) 801ae08745Sheppo { 811ae08745Sheppo 821ae08745Sheppo vntsd_cons_t *consp; 831ae08745Sheppo 841ae08745Sheppo assert(clientp); 851ae08745Sheppo assert(clientp->cons); 861ae08745Sheppo 871ae08745Sheppo consp = clientp->cons; 881ae08745Sheppo D1(stderr, "t@%d genbrk fd=%d sockfd %d\n", thr_self(), 891ae08745Sheppo consp->vcc_fd, clientp->sockfd); 901ae08745Sheppo 911ae08745Sheppo assert(consp->clientpq != NULL); 921ae08745Sheppo if (consp->clientpq->handle != clientp) { 931ae08745Sheppo /* reader */ 941ae08745Sheppo return (vntsd_write_line(clientp, 951ae08745Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG))); 961ae08745Sheppo } 971ae08745Sheppo 981ae08745Sheppo /* writer */ 991ae08745Sheppo if (ioctl(consp->vcc_fd, TCSBRK, NULL)) { 1001ae08745Sheppo return (VNTSD_ERR_VCC_IOCTL); 1011ae08745Sheppo } 1021ae08745Sheppo 1031ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 1041ae08745Sheppo } 1051ae08745Sheppo 1061ae08745Sheppo /* 1071ae08745Sheppo * console_forward() - cycle client to the next console 1081ae08745Sheppo * in the group queue. 1091ae08745Sheppo */ 1101ae08745Sheppo static int 1111ae08745Sheppo console_forward(void) 1121ae08745Sheppo { 1131ae08745Sheppo return (VNTSD_STATUS_MOV_CONS_FORWARD); 1141ae08745Sheppo } 1151ae08745Sheppo 1161ae08745Sheppo /* 1171ae08745Sheppo * console_backward() - cycle client to the previous 1181ae08745Sheppo * console in the group queue. 1191ae08745Sheppo */ 1201ae08745Sheppo static int 1211ae08745Sheppo console_backward(void) 1221ae08745Sheppo { 1231ae08745Sheppo return (VNTSD_STATUS_MOV_CONS_BACKWARD); 1241ae08745Sheppo } 1251ae08745Sheppo 1261ae08745Sheppo /* acquire_write() - acquire write access to a console. */ 1271ae08745Sheppo static int 1281ae08745Sheppo acquire_write(vntsd_client_t *clientp) 1291ae08745Sheppo { 1301ae08745Sheppo int rv; 1311ae08745Sheppo int yes_no = 1; 1321ae08745Sheppo vntsd_cons_t *consp; 1331ae08745Sheppo 1341ae08745Sheppo assert(clientp); 1351ae08745Sheppo consp = clientp->cons; 1361ae08745Sheppo assert(consp); 1371ae08745Sheppo 1381ae08745Sheppo if (consp->clientpq->handle == clientp) { 1391ae08745Sheppo /* client is a writer */ 1401ae08745Sheppo if ((rv = vntsd_write_line(clientp, 1411ae08745Sheppo gettext("You have write permission"))) != 1421ae08745Sheppo VNTSD_SUCCESS) { 1431ae08745Sheppo return (rv); 1441ae08745Sheppo 1451ae08745Sheppo } 1461ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 1471ae08745Sheppo } 1481ae08745Sheppo 1491ae08745Sheppo /* message to client */ 1501ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1511ae08745Sheppo != VNTSD_SUCCESS) { 1521ae08745Sheppo return (rv); 1531ae08745Sheppo } 1541ae08745Sheppo 1551ae08745Sheppo /* 1561ae08745Sheppo * TRANSLATION_NOTE 1571ae08745Sheppo * The following string should be formatted to fit on multiple lines 1581ae08745Sheppo * assuming a line width of at most 78 characters. There must be no 1591ae08745Sheppo * trailing newline. 1601ae08745Sheppo */ 1611ae08745Sheppo if ((rv = vntsd_write_lines(clientp, 1621ae08745Sheppo gettext("Warning: another user currently " 1631ae08745Sheppo "has write permission\nto this console and forcibly removing " 1641ae08745Sheppo "him/her will terminate\nany current write action and all work " 1651ae08745Sheppo "will be lost."))) != VNTSD_SUCCESS) { 1661ae08745Sheppo return (rv); 1671ae08745Sheppo } 1681ae08745Sheppo 1691ae08745Sheppo /* get client yes no */ 1701ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 1711ae08745Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 1721ae08745Sheppo return (rv); 1731ae08745Sheppo } 1741ae08745Sheppo 1751ae08745Sheppo if ((rv = vntsd_get_yes_no(clientp, 1761ae08745Sheppo gettext("Would you like to continue?"), 1771ae08745Sheppo &yes_no)) != VNTSD_SUCCESS) { 1781ae08745Sheppo return (rv); 1791ae08745Sheppo } 1801ae08745Sheppo 1811ae08745Sheppo if (yes_no == B_FALSE) { 1821ae08745Sheppo /* client change mind no need to acquire write access */ 1831ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 1841ae08745Sheppo } 1851ae08745Sheppo 1861ae08745Sheppo return (VNTSD_STATUS_ACQUIRE_WRITER); 1871ae08745Sheppo } 1881ae08745Sheppo 1891ae08745Sheppo /* client_exit() - disconnect client from the console. */ 1901ae08745Sheppo static int 1911ae08745Sheppo client_exit(void) 1921ae08745Sheppo { 1931ae08745Sheppo return (VNTSD_STATUS_RESELECT_CONS); 1941ae08745Sheppo } 1951ae08745Sheppo 1961ae08745Sheppo static int daemon_cmd_help(vntsd_client_t *clientp); 1971ae08745Sheppo 1981ae08745Sheppo /* table for daemon commands */ 1991ae08745Sheppo 2001ae08745Sheppo static esctable_t etable[] = { 2011ae08745Sheppo 2021ae08745Sheppo /* send a break to vcc */ 2038e6a2a04Slm66018 {'#', "Send break", genbrk}, 2041ae08745Sheppo 2051ae08745Sheppo /* exit */ 2068e6a2a04Slm66018 {'.', "Exit from this console", (e_func_t)client_exit}, 2071ae08745Sheppo 2081ae08745Sheppo /* acquire write access */ 2098e6a2a04Slm66018 {'w', "Force write access", acquire_write}, 2101ae08745Sheppo 2111ae08745Sheppo /* connect to next console in queue */ 2128e6a2a04Slm66018 {'n', "Console next", (e_func_t)console_forward}, 2131ae08745Sheppo 2141ae08745Sheppo /* connect to previous console in queue */ 2158e6a2a04Slm66018 {'p', "Console previous", (e_func_t)console_backward}, 2161ae08745Sheppo 2171ae08745Sheppo /* help must be next to last */ 2188e6a2a04Slm66018 {'?', "Help", daemon_cmd_help}, 2191ae08745Sheppo 2201ae08745Sheppo /* table terminator */ 2211ae08745Sheppo {0, 0, 0} 2221ae08745Sheppo }; 2231ae08745Sheppo 2241ae08745Sheppo void 2251ae08745Sheppo vntsd_init_esctable_msgs(void) 2261ae08745Sheppo { 2271ae08745Sheppo esctable_t *p; 2281ae08745Sheppo 2291ae08745Sheppo for (p = etable; p->e_char != '\0'; p++) { 2301ae08745Sheppo p->e_help = gettext(p->e_help); 2311ae08745Sheppo } 2321ae08745Sheppo } 2331ae08745Sheppo 2341ae08745Sheppo /* daemon_cmd_help() - print help. */ 2351ae08745Sheppo static int 2361ae08745Sheppo daemon_cmd_help(vntsd_client_t *clientp) 2371ae08745Sheppo { 2381ae08745Sheppo esctable_t *p; 2391ae08745Sheppo int rv; 2401ae08745Sheppo char buf[VNTSD_LINE_LEN]; 2411ae08745Sheppo 2421ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 2431ae08745Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 2441ae08745Sheppo return (rv); 2451ae08745Sheppo } 2461ae08745Sheppo 2471ae08745Sheppo /* 2481ae08745Sheppo * TRANSLATION_NOTE 2491ae08745Sheppo * VNTSD is the name of the VNTS daemon and should not be translated. 2501ae08745Sheppo */ 2511ae08745Sheppo if ((rv = vntsd_write_line(clientp, gettext("VNTSD commands"))) != 2521ae08745Sheppo VNTSD_SUCCESS) { 2531ae08745Sheppo return (rv); 2541ae08745Sheppo } 2551ae08745Sheppo 2561ae08745Sheppo for (p = etable; p->e_char; p++) { 2571ae08745Sheppo (void) snprintf(buf, sizeof (buf), 2581ae08745Sheppo "~%c --%s", p->e_char, p->e_help); 2591ae08745Sheppo 2601ae08745Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 2611ae08745Sheppo return (rv); 2621ae08745Sheppo } 2631ae08745Sheppo } 2641ae08745Sheppo 2651ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 2661ae08745Sheppo } 2671ae08745Sheppo 2681ae08745Sheppo /* exit from daemon command */ 2691ae08745Sheppo static int 2701ae08745Sheppo exit_daemon_cmd(vntsd_client_t *clientp, int rv) 2711ae08745Sheppo { 2721ae08745Sheppo (void) mutex_lock(&clientp->lock); 2731ae08745Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 2741ae08745Sheppo (void) mutex_unlock(&clientp->lock); 2751ae08745Sheppo return (rv); 2761ae08745Sheppo } 2771ae08745Sheppo 278*d10e4ef2Snarayan /* 279*d10e4ef2Snarayan * vntsd_process_daemon_cmd() - special commands 280*d10e4ef2Snarayan * "<RET>~" vntsd daemon commands 281*d10e4ef2Snarayan * "<RET>~~" enter '~' character 282*d10e4ef2Snarayan */ 2831ae08745Sheppo int 2841ae08745Sheppo vntsd_process_daemon_cmd(vntsd_client_t *clientp, char c) 2851ae08745Sheppo { 2861ae08745Sheppo esctable_t *p; 2871ae08745Sheppo int rv; 288*d10e4ef2Snarayan char prev_char; 2891ae08745Sheppo 290*d10e4ef2Snarayan prev_char = clientp->prev_char; 291*d10e4ef2Snarayan clientp->prev_char = c; 292*d10e4ef2Snarayan 293*d10e4ef2Snarayan if (c != VNTSD_DAEMON_CMD || (prev_char != 0 && prev_char != CR)) { 2941ae08745Sheppo /* not a daemon command */ 2951ae08745Sheppo return (VNTSD_SUCCESS); 2961ae08745Sheppo } 2971ae08745Sheppo 2981ae08745Sheppo if (clientp->status & VNTSD_CLIENT_DISABLE_DAEMON_CMD) { 2991ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 3001ae08745Sheppo } 3011ae08745Sheppo 3021ae08745Sheppo /* no reentry to process_daemon_cmd */ 3031ae08745Sheppo (void) mutex_lock(&clientp->lock); 3041ae08745Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 3051ae08745Sheppo (void) mutex_unlock(&clientp->lock); 3061ae08745Sheppo 3071ae08745Sheppo D3(stderr, "t@%d process_daemon_cmd %d %d \n", thr_self(), 3081ae08745Sheppo clientp->cons->vcc_fd, clientp->sockfd); 3091ae08745Sheppo 3101ae08745Sheppo /* read in command */ 3111ae08745Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 3121ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 3131ae08745Sheppo } 3141ae08745Sheppo 315*d10e4ef2Snarayan clientp->prev_char = c; 316*d10e4ef2Snarayan if (c == VNTSD_DAEMON_CMD) { 317*d10e4ef2Snarayan /* 318*d10e4ef2Snarayan * received another '~' 319*d10e4ef2Snarayan * a user types '~~' to get '~' 320*d10e4ef2Snarayan */ 321*d10e4ef2Snarayan (void) mutex_lock(&clientp->lock); 322*d10e4ef2Snarayan clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 323*d10e4ef2Snarayan (void) mutex_unlock(&clientp->lock); 324*d10e4ef2Snarayan return (VNTSD_SUCCESS); 325*d10e4ef2Snarayan } 326*d10e4ef2Snarayan 3271ae08745Sheppo for (p = etable; p->e_char; p++) { 3281ae08745Sheppo if (p->e_char == c) { 3291ae08745Sheppo /* found match */ 3301ae08745Sheppo assert(p->e_func); 3311ae08745Sheppo rv = (*p->e_func)(clientp); 3321ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 3331ae08745Sheppo } 3341ae08745Sheppo } 3351ae08745Sheppo 3361ae08745Sheppo /* no match, print out the help */ 3371ae08745Sheppo p--; 3381ae08745Sheppo assert(p->e_char == '?'); 3391ae08745Sheppo rv = (*p->e_func)(clientp); 3401ae08745Sheppo 3411ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 3421ae08745Sheppo 3431ae08745Sheppo } 3441ae08745Sheppo 3451ae08745Sheppo /* vntsd_set_telnet_options() - change telnet client to character mode. */ 3461ae08745Sheppo int 3471ae08745Sheppo vntsd_set_telnet_options(int fd) 3481ae08745Sheppo { 3491ae08745Sheppo /* set client telnet options */ 3501ae08745Sheppo uint8_t buf[] = {IAC, DONT, LINEMODE, IAC, WILL, SUPRESS, IAC, WILL, 3511ae08745Sheppo TEL_ECHO, IAC, DONT, TERM_TYPE, IAC, DONT, TERM_SP, 3521ae08745Sheppo IAC, DONT, STATUS, IAC, DONT, FC, IAC, DONT, TM, IAC, DONT, ENV, 3531ae08745Sheppo IAC, DONT, WIN_SIZE}; 3541ae08745Sheppo 3551ae08745Sheppo return (vntsd_write_fd(fd, (char *)buf, 30)); 3561ae08745Sheppo } 3571ae08745Sheppo 3581ae08745Sheppo /* vntsd_telnet_cmd() process telnet commands */ 3591ae08745Sheppo int 3601ae08745Sheppo vntsd_telnet_cmd(vntsd_client_t *clientp, char c) 3611ae08745Sheppo { 3621ae08745Sheppo uint8_t buf[4]; 3631ae08745Sheppo char cmd; 3641ae08745Sheppo int rv = VNTSD_STATUS_CONTINUE; 3651ae08745Sheppo 3661ae08745Sheppo bzero(buf, 4); 3671ae08745Sheppo 3681ae08745Sheppo if ((uint8_t)c != IAC) { 3691ae08745Sheppo /* not telnet cmd */ 3701ae08745Sheppo return (VNTSD_SUCCESS); 3711ae08745Sheppo } 3721ae08745Sheppo 3731ae08745Sheppo if ((rv = vntsd_read_char(clientp, &cmd)) != VNTSD_SUCCESS) { 3741ae08745Sheppo return (rv); 3751ae08745Sheppo } 3761ae08745Sheppo 3771ae08745Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 3781ae08745Sheppo return (rv); 3791ae08745Sheppo } 3801ae08745Sheppo 3811ae08745Sheppo 3821ae08745Sheppo switch ((uint8_t)cmd) { 3831ae08745Sheppo 3841ae08745Sheppo case WILL: 3851ae08745Sheppo 3861ae08745Sheppo switch ((uint8_t)c) { 3871ae08745Sheppo case TEL_ECHO: 3881ae08745Sheppo case SUPRESS: 3891ae08745Sheppo case LINEMODE: 3901ae08745Sheppo break; 3911ae08745Sheppo default: 3921ae08745Sheppo syslog(LOG_ERR, "not support telnet WILL %x\n", c); 3931ae08745Sheppo break; 3941ae08745Sheppo } 3951ae08745Sheppo break; 3961ae08745Sheppo 3971ae08745Sheppo case WONT: 3981ae08745Sheppo 3991ae08745Sheppo switch ((uint8_t)c) { 4001ae08745Sheppo case TEL_ECHO: 4011ae08745Sheppo case SUPRESS: 4021ae08745Sheppo case LINEMODE: 4031ae08745Sheppo default: 4041ae08745Sheppo syslog(LOG_ERR, "not support telnet WONT %x\n", c); 4051ae08745Sheppo break; 4061ae08745Sheppo } 4071ae08745Sheppo break; 4081ae08745Sheppo 4091ae08745Sheppo case DO: 4101ae08745Sheppo case DONT: 4111ae08745Sheppo 4121ae08745Sheppo buf[0] = IAC; 4131ae08745Sheppo buf[1] = WILL; 4141ae08745Sheppo buf[2] = c; 4151ae08745Sheppo rv = vntsd_write_client(clientp, (char *)buf, 3); 4161ae08745Sheppo 4171ae08745Sheppo break; 4181ae08745Sheppo 4191ae08745Sheppo case BRK: 4201ae08745Sheppo 4211ae08745Sheppo /* send break to vcc */ 4221ae08745Sheppo rv = genbrk(clientp); 4231ae08745Sheppo break; 4241ae08745Sheppo 4251ae08745Sheppo case IP: 4261ae08745Sheppo 4271ae08745Sheppo break; 4281ae08745Sheppo 4291ae08745Sheppo case AYT: 4301ae08745Sheppo 4311ae08745Sheppo rv = vntsd_write_client(clientp, &c, 1); 4321ae08745Sheppo break; 4331ae08745Sheppo 4341ae08745Sheppo case HT: 4351ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 4361ae08745Sheppo 4371ae08745Sheppo default: 4381ae08745Sheppo syslog(LOG_ERR, "not support telnet ctrl %x\n", c); 4391ae08745Sheppo break; 4401ae08745Sheppo } 4411ae08745Sheppo 4421ae08745Sheppo if (rv == VNTSD_SUCCESS) { 4431ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 4441ae08745Sheppo } else { 4451ae08745Sheppo return (rv); 4461ae08745Sheppo } 4471ae08745Sheppo } 4481ae08745Sheppo 4491ae08745Sheppo 4501ae08745Sheppo /* 4511ae08745Sheppo * vntsd_ctrl_cmd() - control keys 4521ae08745Sheppo * read and write suspend are supported. 4531ae08745Sheppo */ 4541ae08745Sheppo int 4551ae08745Sheppo vntsd_ctrl_cmd(vntsd_client_t *clientp, char c) 4561ae08745Sheppo { 4571ae08745Sheppo int cmd; 4581ae08745Sheppo 4591ae08745Sheppo D3(stderr, "t@%d vntsd_ctrl_cmd%d %d\n", thr_self(), 4601ae08745Sheppo clientp->cons->vcc_fd, clientp->sockfd); 4611ae08745Sheppo 4621ae08745Sheppo if ((c != START) && (c != STOP)) { 4631ae08745Sheppo /* not a supported control command */ 4641ae08745Sheppo return (VNTSD_SUCCESS); 4651ae08745Sheppo } 4661ae08745Sheppo 4671ae08745Sheppo if (c == START) { 4681ae08745Sheppo 4691ae08745Sheppo D3(stderr, "t@%d client restart\n", thr_self()); 4701ae08745Sheppo 4711ae08745Sheppo /* send resume read */ 4721ae08745Sheppo cmd = 1; 4731ae08745Sheppo 4741ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4751ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4761ae08745Sheppo } 4771ae08745Sheppo 4781ae08745Sheppo /* send resume write */ 4791ae08745Sheppo cmd = 3; 4801ae08745Sheppo 4811ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4821ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4831ae08745Sheppo } 4841ae08745Sheppo } 4851ae08745Sheppo 4861ae08745Sheppo if (c == STOP) { 4871ae08745Sheppo D3(stderr, "t@%d client suspend\n", thr_self()); 4881ae08745Sheppo 4891ae08745Sheppo /* send suspend read */ 4901ae08745Sheppo cmd = 0; 4911ae08745Sheppo 4921ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 4931ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 4941ae08745Sheppo } 4951ae08745Sheppo 4961ae08745Sheppo /* send suspend write */ 4971ae08745Sheppo cmd = 2; 4981ae08745Sheppo 4991ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 5001ae08745Sheppo perror("ioctl TCXONC"); 5011ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 5021ae08745Sheppo } 5031ae08745Sheppo } 5041ae08745Sheppo 5051ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 5061ae08745Sheppo } 507