1*1ae08745Sheppo /* 2*1ae08745Sheppo * CDDL HEADER START 3*1ae08745Sheppo * 4*1ae08745Sheppo * The contents of this file are subject to the terms of the 5*1ae08745Sheppo * Common Development and Distribution License (the "License"). 6*1ae08745Sheppo * You may not use this file except in compliance with the License. 7*1ae08745Sheppo * 8*1ae08745Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*1ae08745Sheppo * or http://www.opensolaris.org/os/licensing. 10*1ae08745Sheppo * See the License for the specific language governing permissions 11*1ae08745Sheppo * and limitations under the License. 12*1ae08745Sheppo * 13*1ae08745Sheppo * When distributing Covered Code, include this CDDL HEADER in each 14*1ae08745Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*1ae08745Sheppo * If applicable, add the following below this CDDL HEADER, with the 16*1ae08745Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 17*1ae08745Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 18*1ae08745Sheppo * 19*1ae08745Sheppo * CDDL HEADER END 20*1ae08745Sheppo */ 21*1ae08745Sheppo /* 22*1ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23*1ae08745Sheppo * Use is subject to license terms. 24*1ae08745Sheppo */ 25*1ae08745Sheppo 26*1ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 27*1ae08745Sheppo 28*1ae08745Sheppo /* 29*1ae08745Sheppo * Vntsd handles two types of special commands, one is telnet 30*1ae08745Sheppo * commands and another is vntsd special commands. 31*1ae08745Sheppo * telnet commands supported are: 32*1ae08745Sheppo * WILL 33*1ae08745Sheppo * WONT 34*1ae08745Sheppo * DO 35*1ae08745Sheppo * DONT 36*1ae08745Sheppo * TEL_ECHO 37*1ae08745Sheppo * SUPRESS 38*1ae08745Sheppo * LINEMODE 39*1ae08745Sheppo * BRK 40*1ae08745Sheppo * AYT 41*1ae08745Sheppo * HT 42*1ae08745Sheppo * 43*1ae08745Sheppo * Vntsd special commands are: 44*1ae08745Sheppo * send break (~#) 45*1ae08745Sheppo * exit (~.) 46*1ae08745Sheppo * force write access (~w) 47*1ae08745Sheppo * cycle console down (~n) 48*1ae08745Sheppo * cycle console up (~p) 49*1ae08745Sheppo * help (~?) 50*1ae08745Sheppo */ 51*1ae08745Sheppo 52*1ae08745Sheppo #include <stdio.h> 53*1ae08745Sheppo #include <stdlib.h> 54*1ae08745Sheppo #include <string.h> 55*1ae08745Sheppo #include <unistd.h> 56*1ae08745Sheppo #include <sys/types.h> 57*1ae08745Sheppo #include <sys/socket.h> 58*1ae08745Sheppo #include <netinet/in.h> 59*1ae08745Sheppo #include <thread.h> 60*1ae08745Sheppo #include <ctype.h> 61*1ae08745Sheppo #include <sys/termio.h> 62*1ae08745Sheppo #include <libintl.h> 63*1ae08745Sheppo #include <syslog.h> 64*1ae08745Sheppo #include "vntsd.h" 65*1ae08745Sheppo #include "chars.h" 66*1ae08745Sheppo 67*1ae08745Sheppo char vntsd_eol[] = { CR, LF, 0}; 68*1ae08745Sheppo 69*1ae08745Sheppo typedef int (*e_func_t)(vntsd_client_t *clientp); 70*1ae08745Sheppo /* structure for daemon special cmd */ 71*1ae08745Sheppo typedef struct { 72*1ae08745Sheppo char e_char; /* char to match on */ 73*1ae08745Sheppo char *e_help; /* help string */ 74*1ae08745Sheppo e_func_t e_func; /* command */ 75*1ae08745Sheppo } esctable_t; 76*1ae08745Sheppo 77*1ae08745Sheppo /* genbrk() - send a break to vcc driver */ 78*1ae08745Sheppo static int 79*1ae08745Sheppo genbrk(vntsd_client_t *clientp) 80*1ae08745Sheppo { 81*1ae08745Sheppo 82*1ae08745Sheppo vntsd_cons_t *consp; 83*1ae08745Sheppo 84*1ae08745Sheppo assert(clientp); 85*1ae08745Sheppo assert(clientp->cons); 86*1ae08745Sheppo 87*1ae08745Sheppo consp = clientp->cons; 88*1ae08745Sheppo D1(stderr, "t@%d genbrk fd=%d sockfd %d\n", thr_self(), 89*1ae08745Sheppo consp->vcc_fd, clientp->sockfd); 90*1ae08745Sheppo 91*1ae08745Sheppo assert(consp->clientpq != NULL); 92*1ae08745Sheppo if (consp->clientpq->handle != clientp) { 93*1ae08745Sheppo /* reader */ 94*1ae08745Sheppo return (vntsd_write_line(clientp, 95*1ae08745Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG))); 96*1ae08745Sheppo } 97*1ae08745Sheppo 98*1ae08745Sheppo /* writer */ 99*1ae08745Sheppo if (ioctl(consp->vcc_fd, TCSBRK, NULL)) { 100*1ae08745Sheppo return (VNTSD_ERR_VCC_IOCTL); 101*1ae08745Sheppo } 102*1ae08745Sheppo 103*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 104*1ae08745Sheppo } 105*1ae08745Sheppo 106*1ae08745Sheppo /* 107*1ae08745Sheppo * console_forward() - cycle client to the next console 108*1ae08745Sheppo * in the group queue. 109*1ae08745Sheppo */ 110*1ae08745Sheppo static int 111*1ae08745Sheppo console_forward(void) 112*1ae08745Sheppo { 113*1ae08745Sheppo return (VNTSD_STATUS_MOV_CONS_FORWARD); 114*1ae08745Sheppo } 115*1ae08745Sheppo 116*1ae08745Sheppo /* 117*1ae08745Sheppo * console_backward() - cycle client to the previous 118*1ae08745Sheppo * console in the group queue. 119*1ae08745Sheppo */ 120*1ae08745Sheppo static int 121*1ae08745Sheppo console_backward(void) 122*1ae08745Sheppo { 123*1ae08745Sheppo return (VNTSD_STATUS_MOV_CONS_BACKWARD); 124*1ae08745Sheppo } 125*1ae08745Sheppo 126*1ae08745Sheppo /* acquire_write() - acquire write access to a console. */ 127*1ae08745Sheppo static int 128*1ae08745Sheppo acquire_write(vntsd_client_t *clientp) 129*1ae08745Sheppo { 130*1ae08745Sheppo int rv; 131*1ae08745Sheppo int yes_no = 1; 132*1ae08745Sheppo vntsd_cons_t *consp; 133*1ae08745Sheppo 134*1ae08745Sheppo assert(clientp); 135*1ae08745Sheppo consp = clientp->cons; 136*1ae08745Sheppo assert(consp); 137*1ae08745Sheppo 138*1ae08745Sheppo if (consp->clientpq->handle == clientp) { 139*1ae08745Sheppo /* client is a writer */ 140*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, 141*1ae08745Sheppo gettext("You have write permission"))) != 142*1ae08745Sheppo VNTSD_SUCCESS) { 143*1ae08745Sheppo return (rv); 144*1ae08745Sheppo 145*1ae08745Sheppo } 146*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 147*1ae08745Sheppo } 148*1ae08745Sheppo 149*1ae08745Sheppo /* message to client */ 150*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 151*1ae08745Sheppo != VNTSD_SUCCESS) { 152*1ae08745Sheppo return (rv); 153*1ae08745Sheppo } 154*1ae08745Sheppo 155*1ae08745Sheppo /* 156*1ae08745Sheppo * TRANSLATION_NOTE 157*1ae08745Sheppo * The following string should be formatted to fit on multiple lines 158*1ae08745Sheppo * assuming a line width of at most 78 characters. There must be no 159*1ae08745Sheppo * trailing newline. 160*1ae08745Sheppo */ 161*1ae08745Sheppo if ((rv = vntsd_write_lines(clientp, 162*1ae08745Sheppo gettext("Warning: another user currently " 163*1ae08745Sheppo "has write permission\nto this console and forcibly removing " 164*1ae08745Sheppo "him/her will terminate\nany current write action and all work " 165*1ae08745Sheppo "will be lost."))) != VNTSD_SUCCESS) { 166*1ae08745Sheppo return (rv); 167*1ae08745Sheppo } 168*1ae08745Sheppo 169*1ae08745Sheppo /* get client yes no */ 170*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 171*1ae08745Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 172*1ae08745Sheppo return (rv); 173*1ae08745Sheppo } 174*1ae08745Sheppo 175*1ae08745Sheppo if ((rv = vntsd_get_yes_no(clientp, 176*1ae08745Sheppo gettext("Would you like to continue?"), 177*1ae08745Sheppo &yes_no)) != VNTSD_SUCCESS) { 178*1ae08745Sheppo return (rv); 179*1ae08745Sheppo } 180*1ae08745Sheppo 181*1ae08745Sheppo if (yes_no == B_FALSE) { 182*1ae08745Sheppo /* client change mind no need to acquire write access */ 183*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 184*1ae08745Sheppo } 185*1ae08745Sheppo 186*1ae08745Sheppo return (VNTSD_STATUS_ACQUIRE_WRITER); 187*1ae08745Sheppo } 188*1ae08745Sheppo 189*1ae08745Sheppo /* client_exit() - disconnect client from the console. */ 190*1ae08745Sheppo static int 191*1ae08745Sheppo client_exit(void) 192*1ae08745Sheppo { 193*1ae08745Sheppo return (VNTSD_STATUS_RESELECT_CONS); 194*1ae08745Sheppo } 195*1ae08745Sheppo 196*1ae08745Sheppo static int daemon_cmd_help(vntsd_client_t *clientp); 197*1ae08745Sheppo 198*1ae08745Sheppo /* table for daemon commands */ 199*1ae08745Sheppo 200*1ae08745Sheppo static esctable_t etable[] = { 201*1ae08745Sheppo 202*1ae08745Sheppo /* send a break to vcc */ 203*1ae08745Sheppo {'#', "send break", genbrk}, 204*1ae08745Sheppo 205*1ae08745Sheppo /* exit */ 206*1ae08745Sheppo {'.', "exit from this console", (e_func_t)client_exit}, 207*1ae08745Sheppo 208*1ae08745Sheppo /* acquire write access */ 209*1ae08745Sheppo {'w', "force write access", acquire_write}, 210*1ae08745Sheppo 211*1ae08745Sheppo /* connect to next console in queue */ 212*1ae08745Sheppo {'n', "console down", (e_func_t)console_forward}, 213*1ae08745Sheppo 214*1ae08745Sheppo /* connect to previous console in queue */ 215*1ae08745Sheppo {'p', "console up", (e_func_t)console_backward}, 216*1ae08745Sheppo 217*1ae08745Sheppo /* help must be next to last */ 218*1ae08745Sheppo {'?', "_", daemon_cmd_help}, 219*1ae08745Sheppo 220*1ae08745Sheppo /* table terminator */ 221*1ae08745Sheppo {0, 0, 0} 222*1ae08745Sheppo }; 223*1ae08745Sheppo 224*1ae08745Sheppo void 225*1ae08745Sheppo vntsd_init_esctable_msgs(void) 226*1ae08745Sheppo { 227*1ae08745Sheppo esctable_t *p; 228*1ae08745Sheppo 229*1ae08745Sheppo for (p = etable; p->e_char != '\0'; p++) { 230*1ae08745Sheppo p->e_help = gettext(p->e_help); 231*1ae08745Sheppo } 232*1ae08745Sheppo } 233*1ae08745Sheppo 234*1ae08745Sheppo /* daemon_cmd_help() - print help. */ 235*1ae08745Sheppo static int 236*1ae08745Sheppo daemon_cmd_help(vntsd_client_t *clientp) 237*1ae08745Sheppo { 238*1ae08745Sheppo esctable_t *p; 239*1ae08745Sheppo int rv; 240*1ae08745Sheppo char buf[VNTSD_LINE_LEN]; 241*1ae08745Sheppo 242*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, 243*1ae08745Sheppo VNTSD_EOL_LEN)) != VNTSD_SUCCESS) { 244*1ae08745Sheppo return (rv); 245*1ae08745Sheppo } 246*1ae08745Sheppo 247*1ae08745Sheppo /* 248*1ae08745Sheppo * TRANSLATION_NOTE 249*1ae08745Sheppo * VNTSD is the name of the VNTS daemon and should not be translated. 250*1ae08745Sheppo */ 251*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, gettext("VNTSD commands"))) != 252*1ae08745Sheppo VNTSD_SUCCESS) { 253*1ae08745Sheppo return (rv); 254*1ae08745Sheppo } 255*1ae08745Sheppo 256*1ae08745Sheppo for (p = etable; p->e_char; p++) { 257*1ae08745Sheppo (void) snprintf(buf, sizeof (buf), 258*1ae08745Sheppo "~%c --%s", p->e_char, p->e_help); 259*1ae08745Sheppo 260*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 261*1ae08745Sheppo return (rv); 262*1ae08745Sheppo } 263*1ae08745Sheppo } 264*1ae08745Sheppo 265*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 266*1ae08745Sheppo } 267*1ae08745Sheppo 268*1ae08745Sheppo /* exit from daemon command */ 269*1ae08745Sheppo static int 270*1ae08745Sheppo exit_daemon_cmd(vntsd_client_t *clientp, int rv) 271*1ae08745Sheppo { 272*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 273*1ae08745Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 274*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 275*1ae08745Sheppo return (rv); 276*1ae08745Sheppo } 277*1ae08745Sheppo 278*1ae08745Sheppo /* vntsd_process_daemon_cmd() - special commands */ 279*1ae08745Sheppo int 280*1ae08745Sheppo vntsd_process_daemon_cmd(vntsd_client_t *clientp, char c) 281*1ae08745Sheppo { 282*1ae08745Sheppo esctable_t *p; 283*1ae08745Sheppo int rv; 284*1ae08745Sheppo 285*1ae08745Sheppo if (c != VNTSD_DAEMON_CMD) { 286*1ae08745Sheppo /* not a daemon command */ 287*1ae08745Sheppo return (VNTSD_SUCCESS); 288*1ae08745Sheppo } 289*1ae08745Sheppo 290*1ae08745Sheppo if (clientp->status & VNTSD_CLIENT_DISABLE_DAEMON_CMD) { 291*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 292*1ae08745Sheppo } 293*1ae08745Sheppo 294*1ae08745Sheppo /* no reentry to process_daemon_cmd */ 295*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 296*1ae08745Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 297*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 298*1ae08745Sheppo 299*1ae08745Sheppo D3(stderr, "t@%d process_daemon_cmd %d %d \n", thr_self(), 300*1ae08745Sheppo clientp->cons->vcc_fd, clientp->sockfd); 301*1ae08745Sheppo 302*1ae08745Sheppo /* read in command */ 303*1ae08745Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 304*1ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 305*1ae08745Sheppo } 306*1ae08745Sheppo 307*1ae08745Sheppo for (p = etable; p->e_char; p++) { 308*1ae08745Sheppo if (p->e_char == c) { 309*1ae08745Sheppo /* found match */ 310*1ae08745Sheppo assert(p->e_func); 311*1ae08745Sheppo rv = (*p->e_func)(clientp); 312*1ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 313*1ae08745Sheppo } 314*1ae08745Sheppo } 315*1ae08745Sheppo 316*1ae08745Sheppo /* no match, print out the help */ 317*1ae08745Sheppo p--; 318*1ae08745Sheppo assert(p->e_char == '?'); 319*1ae08745Sheppo rv = (*p->e_func)(clientp); 320*1ae08745Sheppo 321*1ae08745Sheppo return (exit_daemon_cmd(clientp, rv)); 322*1ae08745Sheppo 323*1ae08745Sheppo } 324*1ae08745Sheppo 325*1ae08745Sheppo /* vntsd_set_telnet_options() - change telnet client to character mode. */ 326*1ae08745Sheppo int 327*1ae08745Sheppo vntsd_set_telnet_options(int fd) 328*1ae08745Sheppo { 329*1ae08745Sheppo /* set client telnet options */ 330*1ae08745Sheppo uint8_t buf[] = {IAC, DONT, LINEMODE, IAC, WILL, SUPRESS, IAC, WILL, 331*1ae08745Sheppo TEL_ECHO, IAC, DONT, TERM_TYPE, IAC, DONT, TERM_SP, 332*1ae08745Sheppo IAC, DONT, STATUS, IAC, DONT, FC, IAC, DONT, TM, IAC, DONT, ENV, 333*1ae08745Sheppo IAC, DONT, WIN_SIZE}; 334*1ae08745Sheppo 335*1ae08745Sheppo return (vntsd_write_fd(fd, (char *)buf, 30)); 336*1ae08745Sheppo } 337*1ae08745Sheppo 338*1ae08745Sheppo /* vntsd_telnet_cmd() process telnet commands */ 339*1ae08745Sheppo int 340*1ae08745Sheppo vntsd_telnet_cmd(vntsd_client_t *clientp, char c) 341*1ae08745Sheppo { 342*1ae08745Sheppo uint8_t buf[4]; 343*1ae08745Sheppo char cmd; 344*1ae08745Sheppo int rv = VNTSD_STATUS_CONTINUE; 345*1ae08745Sheppo 346*1ae08745Sheppo bzero(buf, 4); 347*1ae08745Sheppo 348*1ae08745Sheppo if ((uint8_t)c != IAC) { 349*1ae08745Sheppo /* not telnet cmd */ 350*1ae08745Sheppo return (VNTSD_SUCCESS); 351*1ae08745Sheppo } 352*1ae08745Sheppo 353*1ae08745Sheppo if ((rv = vntsd_read_char(clientp, &cmd)) != VNTSD_SUCCESS) { 354*1ae08745Sheppo return (rv); 355*1ae08745Sheppo } 356*1ae08745Sheppo 357*1ae08745Sheppo if ((rv = vntsd_read_char(clientp, &c)) != VNTSD_SUCCESS) { 358*1ae08745Sheppo return (rv); 359*1ae08745Sheppo } 360*1ae08745Sheppo 361*1ae08745Sheppo 362*1ae08745Sheppo switch ((uint8_t)cmd) { 363*1ae08745Sheppo 364*1ae08745Sheppo case WILL: 365*1ae08745Sheppo 366*1ae08745Sheppo switch ((uint8_t)c) { 367*1ae08745Sheppo case TEL_ECHO: 368*1ae08745Sheppo case SUPRESS: 369*1ae08745Sheppo case LINEMODE: 370*1ae08745Sheppo break; 371*1ae08745Sheppo default: 372*1ae08745Sheppo syslog(LOG_ERR, "not support telnet WILL %x\n", c); 373*1ae08745Sheppo break; 374*1ae08745Sheppo } 375*1ae08745Sheppo break; 376*1ae08745Sheppo 377*1ae08745Sheppo case WONT: 378*1ae08745Sheppo 379*1ae08745Sheppo switch ((uint8_t)c) { 380*1ae08745Sheppo case TEL_ECHO: 381*1ae08745Sheppo case SUPRESS: 382*1ae08745Sheppo case LINEMODE: 383*1ae08745Sheppo default: 384*1ae08745Sheppo syslog(LOG_ERR, "not support telnet WONT %x\n", c); 385*1ae08745Sheppo break; 386*1ae08745Sheppo } 387*1ae08745Sheppo break; 388*1ae08745Sheppo 389*1ae08745Sheppo case DO: 390*1ae08745Sheppo case DONT: 391*1ae08745Sheppo 392*1ae08745Sheppo buf[0] = IAC; 393*1ae08745Sheppo buf[1] = WILL; 394*1ae08745Sheppo buf[2] = c; 395*1ae08745Sheppo rv = vntsd_write_client(clientp, (char *)buf, 3); 396*1ae08745Sheppo 397*1ae08745Sheppo break; 398*1ae08745Sheppo 399*1ae08745Sheppo case BRK: 400*1ae08745Sheppo 401*1ae08745Sheppo /* send break to vcc */ 402*1ae08745Sheppo rv = genbrk(clientp); 403*1ae08745Sheppo break; 404*1ae08745Sheppo 405*1ae08745Sheppo case IP: 406*1ae08745Sheppo 407*1ae08745Sheppo break; 408*1ae08745Sheppo 409*1ae08745Sheppo case AYT: 410*1ae08745Sheppo 411*1ae08745Sheppo rv = vntsd_write_client(clientp, &c, 1); 412*1ae08745Sheppo break; 413*1ae08745Sheppo 414*1ae08745Sheppo case HT: 415*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 416*1ae08745Sheppo 417*1ae08745Sheppo default: 418*1ae08745Sheppo syslog(LOG_ERR, "not support telnet ctrl %x\n", c); 419*1ae08745Sheppo break; 420*1ae08745Sheppo } 421*1ae08745Sheppo 422*1ae08745Sheppo if (rv == VNTSD_SUCCESS) { 423*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 424*1ae08745Sheppo } else { 425*1ae08745Sheppo return (rv); 426*1ae08745Sheppo } 427*1ae08745Sheppo } 428*1ae08745Sheppo 429*1ae08745Sheppo 430*1ae08745Sheppo /* 431*1ae08745Sheppo * vntsd_ctrl_cmd() - control keys 432*1ae08745Sheppo * read and write suspend are supported. 433*1ae08745Sheppo */ 434*1ae08745Sheppo int 435*1ae08745Sheppo vntsd_ctrl_cmd(vntsd_client_t *clientp, char c) 436*1ae08745Sheppo { 437*1ae08745Sheppo int cmd; 438*1ae08745Sheppo 439*1ae08745Sheppo D3(stderr, "t@%d vntsd_ctrl_cmd%d %d\n", thr_self(), 440*1ae08745Sheppo clientp->cons->vcc_fd, clientp->sockfd); 441*1ae08745Sheppo 442*1ae08745Sheppo if ((c != START) && (c != STOP)) { 443*1ae08745Sheppo /* not a supported control command */ 444*1ae08745Sheppo return (VNTSD_SUCCESS); 445*1ae08745Sheppo } 446*1ae08745Sheppo 447*1ae08745Sheppo if (c == START) { 448*1ae08745Sheppo 449*1ae08745Sheppo D3(stderr, "t@%d client restart\n", thr_self()); 450*1ae08745Sheppo 451*1ae08745Sheppo /* send resume read */ 452*1ae08745Sheppo cmd = 1; 453*1ae08745Sheppo 454*1ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 455*1ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 456*1ae08745Sheppo } 457*1ae08745Sheppo 458*1ae08745Sheppo /* send resume write */ 459*1ae08745Sheppo cmd = 3; 460*1ae08745Sheppo 461*1ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 462*1ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 463*1ae08745Sheppo } 464*1ae08745Sheppo } 465*1ae08745Sheppo 466*1ae08745Sheppo if (c == STOP) { 467*1ae08745Sheppo D3(stderr, "t@%d client suspend\n", thr_self()); 468*1ae08745Sheppo 469*1ae08745Sheppo /* send suspend read */ 470*1ae08745Sheppo cmd = 0; 471*1ae08745Sheppo 472*1ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 473*1ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 474*1ae08745Sheppo } 475*1ae08745Sheppo 476*1ae08745Sheppo /* send suspend write */ 477*1ae08745Sheppo cmd = 2; 478*1ae08745Sheppo 479*1ae08745Sheppo if (ioctl(clientp->cons->vcc_fd, TCXONC, &cmd)) { 480*1ae08745Sheppo perror("ioctl TCXONC"); 481*1ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 482*1ae08745Sheppo } 483*1ae08745Sheppo } 484*1ae08745Sheppo 485*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 486*1ae08745Sheppo } 487