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 #pragma ident "%Z%%M% %I% %E% SMI" 221ae08745Sheppo 231ae08745Sheppo /* 24*1f79c0b8Sdtse * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 251ae08745Sheppo * Use is subject to license terms. 261ae08745Sheppo */ 271ae08745Sheppo 281ae08745Sheppo /* 291ae08745Sheppo * read thread - Read from tcp client and write to vcc driver. There are one 301ae08745Sheppo * writer and multiple readers per console. The first client who connects to 311ae08745Sheppo * a console get write access. An error message is returned to readers if they 321ae08745Sheppo * attemp to input commands. Read thread accepts special daemon commands from 331ae08745Sheppo * all clients. 341ae08745Sheppo */ 351ae08745Sheppo 361ae08745Sheppo #include <stdio.h> 371ae08745Sheppo #include <stdlib.h> 381ae08745Sheppo #include <string.h> 391ae08745Sheppo #include <unistd.h> 401ae08745Sheppo #include <sys/types.h> 411ae08745Sheppo #include <sys/socket.h> 421ae08745Sheppo #include <netinet/in.h> 431ae08745Sheppo #include <thread.h> 441ae08745Sheppo #include <synch.h> 451ae08745Sheppo #include <signal.h> 461ae08745Sheppo #include <assert.h> 471ae08745Sheppo #include <ctype.h> 481ae08745Sheppo #include <syslog.h> 491ae08745Sheppo #include <libintl.h> 501ae08745Sheppo #include "vntsd.h" 511ae08745Sheppo #include "chars.h" 521ae08745Sheppo 531ae08745Sheppo /* write_vcc() - write to vcc virtual console */ 541ae08745Sheppo static int 551ae08745Sheppo write_vcc(vntsd_client_t *clientp, char c) 561ae08745Sheppo { 571ae08745Sheppo int n; 581ae08745Sheppo 591ae08745Sheppo 601ae08745Sheppo assert(clientp); 611ae08745Sheppo assert(clientp->cons); 621ae08745Sheppo 631ae08745Sheppo n = write(clientp->cons->vcc_fd, &c, 1); 641ae08745Sheppo 651ae08745Sheppo if (n < 0) { 661ae08745Sheppo /* write error */ 671ae08745Sheppo if (errno == EINTR) { 681ae08745Sheppo return (vntsd_cons_chk_intr(clientp)); 691ae08745Sheppo } 701ae08745Sheppo 711ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 721ae08745Sheppo } 731ae08745Sheppo 741ae08745Sheppo assert(n != 0); 751ae08745Sheppo return (VNTSD_SUCCESS); 761ae08745Sheppo 771ae08745Sheppo } 781ae08745Sheppo 791ae08745Sheppo /* 801ae08745Sheppo * acquire_writer() the client is going to be writer. 811ae08745Sheppo * insert the client to the head of the console client queue. 821ae08745Sheppo */ 831ae08745Sheppo static int 841ae08745Sheppo acquire_writer(vntsd_client_t *clientp) 851ae08745Sheppo { 861ae08745Sheppo vntsd_cons_t *consp; 871ae08745Sheppo vntsd_client_t *writerp; 881ae08745Sheppo int rv; 891ae08745Sheppo 901ae08745Sheppo D1(stderr, "t@%d:acuire_writer :client@%d\n", thr_self(), 911ae08745Sheppo clientp->sockfd); 921ae08745Sheppo 931ae08745Sheppo assert(clientp != NULL); 941ae08745Sheppo consp = clientp->cons; 951ae08745Sheppo 961ae08745Sheppo assert(consp); 971ae08745Sheppo 981ae08745Sheppo (void) mutex_lock(&consp->lock); 991ae08745Sheppo 1001ae08745Sheppo assert(consp->clientpq != NULL); 1011ae08745Sheppo if (consp->clientpq->handle == clientp) { 1021ae08745Sheppo /* clientp is a writer already */ 1031ae08745Sheppo (void) mutex_unlock(&consp->lock); 1041ae08745Sheppo return (VNTSD_SUCCESS); 1051ae08745Sheppo } 1061ae08745Sheppo 1071ae08745Sheppo /* current writer */ 1081ae08745Sheppo writerp = (vntsd_client_t *)(consp->clientpq->handle); 1091ae08745Sheppo 1101ae08745Sheppo (void) mutex_lock(&writerp->lock); 1111ae08745Sheppo 1121ae08745Sheppo rv = vntsd_que_rm(&(consp->clientpq), clientp); 1131ae08745Sheppo assert(rv == VNTSD_SUCCESS); 1141ae08745Sheppo 1151ae08745Sheppo (void) mutex_lock(&clientp->lock); 1161ae08745Sheppo 1171ae08745Sheppo /* move client to be first in the console queue */ 1181ae08745Sheppo consp->clientpq->handle = clientp; 1191ae08745Sheppo 1201ae08745Sheppo /* move previous writer to be the second in the queue */ 1211ae08745Sheppo rv = vntsd_que_insert_after(consp->clientpq, clientp, writerp); 1221ae08745Sheppo 1231ae08745Sheppo (void) mutex_unlock(&consp->lock); 1241ae08745Sheppo (void) mutex_unlock(&writerp->lock); 1251ae08745Sheppo (void) mutex_unlock(&clientp->lock); 1261ae08745Sheppo 1271ae08745Sheppo if (rv != VNTSD_SUCCESS) { 1281ae08745Sheppo return (rv); 1291ae08745Sheppo } 1301ae08745Sheppo 1311ae08745Sheppo /* write warning message to the writer */ 1321ae08745Sheppo 1331ae08745Sheppo if ((rv = vntsd_write_line(writerp, 1341ae08745Sheppo gettext("Warning: Console connection forced into read-only mode"))) 1351ae08745Sheppo != VNTSD_SUCCESS) { 1361ae08745Sheppo return (rv); 1371ae08745Sheppo } 1381ae08745Sheppo 1391ae08745Sheppo return (VNTSD_SUCCESS); 1401ae08745Sheppo } 1411ae08745Sheppo 1421ae08745Sheppo /* interrupt handler */ 1431ae08745Sheppo int 1441ae08745Sheppo vntsd_cons_chk_intr(vntsd_client_t *clientp) 1451ae08745Sheppo { 1461ae08745Sheppo 1471ae08745Sheppo if (clientp->status & VNTSD_CLIENT_TIMEOUT) { 1481ae08745Sheppo return (VNTSD_STATUS_CLIENT_QUIT); 1491ae08745Sheppo } 1501ae08745Sheppo if (clientp->status & VNTSD_CLIENT_CONS_DELETED) { 1511ae08745Sheppo return (VNTSD_STATUS_RESELECT_CONS); 1521ae08745Sheppo } 1531ae08745Sheppo 1541ae08745Sheppo if (clientp->status & VNTSD_CLIENT_IO_ERR) { 1551ae08745Sheppo return (VNTSD_STATUS_CLIENT_QUIT); 1561ae08745Sheppo } 1571ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 1581ae08745Sheppo } 1591ae08745Sheppo 1601ae08745Sheppo /* read from client */ 1611ae08745Sheppo static int 1621ae08745Sheppo read_char(vntsd_client_t *clientp, char *c) 1631ae08745Sheppo { 1641ae08745Sheppo int rv; 1651ae08745Sheppo 1661ae08745Sheppo for (; ; ) { 1671ae08745Sheppo 1681ae08745Sheppo rv = vntsd_read_data(clientp, c); 1691ae08745Sheppo 1701ae08745Sheppo switch (rv) { 1711ae08745Sheppo 1721ae08745Sheppo case VNTSD_STATUS_ACQUIRE_WRITER: 173823fe29bSdtse clientp->prev_char = 0; 1741ae08745Sheppo rv = acquire_writer(clientp); 1751ae08745Sheppo if (rv != VNTSD_SUCCESS) { 1761ae08745Sheppo return (rv); 1771ae08745Sheppo } 1781ae08745Sheppo break; 179823fe29bSdtse 180823fe29bSdtse case VNTSD_SUCCESS: 181823fe29bSdtse /* 182823fe29bSdtse * Based on telnet protocol, when an <eol> is entered, 183823fe29bSdtse * vntsd receives <0x0d,0x00>. However, console expects 184823fe29bSdtse * <0xd> only. We need to filter out <0x00>. 185823fe29bSdtse */ 186823fe29bSdtse if (clientp->prev_char == 0xd && *c == 0) { 187823fe29bSdtse clientp->prev_char = *c; 188823fe29bSdtse break; 189823fe29bSdtse } 190823fe29bSdtse 191823fe29bSdtse clientp->prev_char = *c; 1921ae08745Sheppo return (rv); 193823fe29bSdtse 194823fe29bSdtse default: 195823fe29bSdtse assert(rv != VNTSD_STATUS_CONTINUE); 196823fe29bSdtse clientp->prev_char = 0; 197823fe29bSdtse return (rv); 198823fe29bSdtse 1991ae08745Sheppo } 2001ae08745Sheppo } 2011ae08745Sheppo } 2021ae08745Sheppo 2031ae08745Sheppo /* vntsd_read worker */ 2041ae08745Sheppo int 2051ae08745Sheppo vntsd_read(vntsd_client_t *clientp) 2061ae08745Sheppo { 2071ae08745Sheppo char c; 2081ae08745Sheppo int rv; 2091ae08745Sheppo 2101ae08745Sheppo 2111ae08745Sheppo assert(clientp); 2121ae08745Sheppo D3(stderr, "t@%d vntsd_read@%d\n", thr_self(), clientp->sockfd); 2131ae08745Sheppo 2141ae08745Sheppo for (; ; ) { 2151ae08745Sheppo 2161ae08745Sheppo /* client input */ 2171ae08745Sheppo rv = read_char(clientp, &c); 2181ae08745Sheppo 2191ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 2201ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 2211ae08745Sheppo } 2221ae08745Sheppo 2231ae08745Sheppo if (rv != VNTSD_SUCCESS) { 2241ae08745Sheppo return (rv); 2251ae08745Sheppo } 2261ae08745Sheppo 2271ae08745Sheppo assert(clientp->cons); 228*1f79c0b8Sdtse 229*1f79c0b8Sdtse /* 230*1f79c0b8Sdtse * Only keyboard inputs from first connection to a 231*1f79c0b8Sdtse * guest console should be accepted. Check to see if 232*1f79c0b8Sdtse * this client is the first connection in console 233*1f79c0b8Sdtse * queue 234*1f79c0b8Sdtse */ 2351ae08745Sheppo if (clientp->cons->clientpq->handle != clientp) { 236*1f79c0b8Sdtse /* 237*1f79c0b8Sdtse * Since this console connection is not the first 238*1f79c0b8Sdtse * connection in the console queue, 239*1f79c0b8Sdtse * it is operating in 'reader' 240*1f79c0b8Sdtse * mode, print warning and ignore the input. 241*1f79c0b8Sdtse */ 2421ae08745Sheppo rv = vntsd_write_line(clientp, 2431ae08745Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG)); 2441ae08745Sheppo 245*1f79c0b8Sdtse /* check errors and interrupts */ 2461ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 2471ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 2481ae08745Sheppo } 2491ae08745Sheppo 2501ae08745Sheppo if (rv != VNTSD_SUCCESS) { 2511ae08745Sheppo return (rv); 2521ae08745Sheppo } 2531ae08745Sheppo 2541ae08745Sheppo continue; 2551ae08745Sheppo } 2561ae08745Sheppo 2571ae08745Sheppo rv = vntsd_ctrl_cmd(clientp, c); 2581ae08745Sheppo 2591ae08745Sheppo switch (rv) { 2601ae08745Sheppo case VNTSD_STATUS_CONTINUE: 2611ae08745Sheppo continue; 2621ae08745Sheppo break; 2631ae08745Sheppo case VNTSD_STATUS_INTR: 2641ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 2651ae08745Sheppo if (rv != VNTSD_SUCCESS) { 2661ae08745Sheppo return (rv); 2671ae08745Sheppo } 2681ae08745Sheppo break; 2691ae08745Sheppo case VNTSD_SUCCESS: 2701ae08745Sheppo break; 2711ae08745Sheppo default: 2721ae08745Sheppo return (rv); 2731ae08745Sheppo } 2741ae08745Sheppo 2751ae08745Sheppo /* write to vcc */ 2761ae08745Sheppo rv = write_vcc(clientp, c); 2771ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 2781ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 2791ae08745Sheppo } 2801ae08745Sheppo if (rv != VNTSD_SUCCESS) { 2811ae08745Sheppo return (rv); 2821ae08745Sheppo } 2831ae08745Sheppo 2841ae08745Sheppo } 2851ae08745Sheppo 2861ae08745Sheppo /*NOTREACHED*/ 2871ae08745Sheppo return (NULL); 2881ae08745Sheppo } 289