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 #pragma ident "%Z%%M% %I% %E% SMI" 22*1ae08745Sheppo 23*1ae08745Sheppo /* 24*1ae08745Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 25*1ae08745Sheppo * Use is subject to license terms. 26*1ae08745Sheppo */ 27*1ae08745Sheppo 28*1ae08745Sheppo /* 29*1ae08745Sheppo * read thread - Read from tcp client and write to vcc driver. There are one 30*1ae08745Sheppo * writer and multiple readers per console. The first client who connects to 31*1ae08745Sheppo * a console get write access. An error message is returned to readers if they 32*1ae08745Sheppo * attemp to input commands. Read thread accepts special daemon commands from 33*1ae08745Sheppo * all clients. 34*1ae08745Sheppo */ 35*1ae08745Sheppo 36*1ae08745Sheppo #include <stdio.h> 37*1ae08745Sheppo #include <stdlib.h> 38*1ae08745Sheppo #include <string.h> 39*1ae08745Sheppo #include <unistd.h> 40*1ae08745Sheppo #include <sys/types.h> 41*1ae08745Sheppo #include <sys/socket.h> 42*1ae08745Sheppo #include <netinet/in.h> 43*1ae08745Sheppo #include <thread.h> 44*1ae08745Sheppo #include <synch.h> 45*1ae08745Sheppo #include <signal.h> 46*1ae08745Sheppo #include <assert.h> 47*1ae08745Sheppo #include <ctype.h> 48*1ae08745Sheppo #include <syslog.h> 49*1ae08745Sheppo #include <libintl.h> 50*1ae08745Sheppo #include "vntsd.h" 51*1ae08745Sheppo #include "chars.h" 52*1ae08745Sheppo 53*1ae08745Sheppo /* write_vcc() - write to vcc virtual console */ 54*1ae08745Sheppo static int 55*1ae08745Sheppo write_vcc(vntsd_client_t *clientp, char c) 56*1ae08745Sheppo { 57*1ae08745Sheppo int n; 58*1ae08745Sheppo 59*1ae08745Sheppo 60*1ae08745Sheppo assert(clientp); 61*1ae08745Sheppo assert(clientp->cons); 62*1ae08745Sheppo 63*1ae08745Sheppo if (c == 0) { 64*1ae08745Sheppo return (VNTSD_SUCCESS); 65*1ae08745Sheppo } 66*1ae08745Sheppo n = write(clientp->cons->vcc_fd, &c, 1); 67*1ae08745Sheppo 68*1ae08745Sheppo if (n < 0) { 69*1ae08745Sheppo /* write error */ 70*1ae08745Sheppo if (errno == EINTR) { 71*1ae08745Sheppo return (vntsd_cons_chk_intr(clientp)); 72*1ae08745Sheppo } 73*1ae08745Sheppo 74*1ae08745Sheppo return (VNTSD_STATUS_VCC_IO_ERR); 75*1ae08745Sheppo } 76*1ae08745Sheppo 77*1ae08745Sheppo assert(n != 0); 78*1ae08745Sheppo return (VNTSD_SUCCESS); 79*1ae08745Sheppo 80*1ae08745Sheppo } 81*1ae08745Sheppo 82*1ae08745Sheppo /* 83*1ae08745Sheppo * acquire_writer() the client is going to be writer. 84*1ae08745Sheppo * insert the client to the head of the console client queue. 85*1ae08745Sheppo */ 86*1ae08745Sheppo static int 87*1ae08745Sheppo acquire_writer(vntsd_client_t *clientp) 88*1ae08745Sheppo { 89*1ae08745Sheppo vntsd_cons_t *consp; 90*1ae08745Sheppo vntsd_client_t *writerp; 91*1ae08745Sheppo int rv; 92*1ae08745Sheppo 93*1ae08745Sheppo D1(stderr, "t@%d:acuire_writer :client@%d\n", thr_self(), 94*1ae08745Sheppo clientp->sockfd); 95*1ae08745Sheppo 96*1ae08745Sheppo assert(clientp != NULL); 97*1ae08745Sheppo consp = clientp->cons; 98*1ae08745Sheppo 99*1ae08745Sheppo assert(consp); 100*1ae08745Sheppo 101*1ae08745Sheppo (void) mutex_lock(&consp->lock); 102*1ae08745Sheppo 103*1ae08745Sheppo assert(consp->clientpq != NULL); 104*1ae08745Sheppo if (consp->clientpq->handle == clientp) { 105*1ae08745Sheppo /* clientp is a writer already */ 106*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 107*1ae08745Sheppo return (VNTSD_SUCCESS); 108*1ae08745Sheppo } 109*1ae08745Sheppo 110*1ae08745Sheppo /* current writer */ 111*1ae08745Sheppo writerp = (vntsd_client_t *)(consp->clientpq->handle); 112*1ae08745Sheppo 113*1ae08745Sheppo (void) mutex_lock(&writerp->lock); 114*1ae08745Sheppo 115*1ae08745Sheppo rv = vntsd_que_rm(&(consp->clientpq), clientp); 116*1ae08745Sheppo assert(rv == VNTSD_SUCCESS); 117*1ae08745Sheppo 118*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 119*1ae08745Sheppo 120*1ae08745Sheppo /* move client to be first in the console queue */ 121*1ae08745Sheppo consp->clientpq->handle = clientp; 122*1ae08745Sheppo 123*1ae08745Sheppo /* move previous writer to be the second in the queue */ 124*1ae08745Sheppo rv = vntsd_que_insert_after(consp->clientpq, clientp, writerp); 125*1ae08745Sheppo 126*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 127*1ae08745Sheppo (void) mutex_unlock(&writerp->lock); 128*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 129*1ae08745Sheppo 130*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 131*1ae08745Sheppo return (rv); 132*1ae08745Sheppo } 133*1ae08745Sheppo 134*1ae08745Sheppo /* write warning message to the writer */ 135*1ae08745Sheppo 136*1ae08745Sheppo if ((rv = vntsd_write_line(writerp, 137*1ae08745Sheppo gettext("Warning: Console connection forced into read-only mode"))) 138*1ae08745Sheppo != VNTSD_SUCCESS) { 139*1ae08745Sheppo return (rv); 140*1ae08745Sheppo } 141*1ae08745Sheppo 142*1ae08745Sheppo return (VNTSD_SUCCESS); 143*1ae08745Sheppo } 144*1ae08745Sheppo 145*1ae08745Sheppo /* interrupt handler */ 146*1ae08745Sheppo int 147*1ae08745Sheppo vntsd_cons_chk_intr(vntsd_client_t *clientp) 148*1ae08745Sheppo { 149*1ae08745Sheppo 150*1ae08745Sheppo if (clientp->status & VNTSD_CLIENT_TIMEOUT) { 151*1ae08745Sheppo return (VNTSD_STATUS_CLIENT_QUIT); 152*1ae08745Sheppo } 153*1ae08745Sheppo if (clientp->status & VNTSD_CLIENT_CONS_DELETED) { 154*1ae08745Sheppo return (VNTSD_STATUS_RESELECT_CONS); 155*1ae08745Sheppo } 156*1ae08745Sheppo 157*1ae08745Sheppo if (clientp->status & VNTSD_CLIENT_IO_ERR) { 158*1ae08745Sheppo return (VNTSD_STATUS_CLIENT_QUIT); 159*1ae08745Sheppo } 160*1ae08745Sheppo return (VNTSD_STATUS_CONTINUE); 161*1ae08745Sheppo } 162*1ae08745Sheppo 163*1ae08745Sheppo /* read from client */ 164*1ae08745Sheppo static int 165*1ae08745Sheppo read_char(vntsd_client_t *clientp, char *c) 166*1ae08745Sheppo { 167*1ae08745Sheppo int rv; 168*1ae08745Sheppo 169*1ae08745Sheppo for (; ; ) { 170*1ae08745Sheppo 171*1ae08745Sheppo rv = vntsd_read_data(clientp, c); 172*1ae08745Sheppo 173*1ae08745Sheppo switch (rv) { 174*1ae08745Sheppo case VNTSD_STATUS_CONTINUE: 175*1ae08745Sheppo break; 176*1ae08745Sheppo 177*1ae08745Sheppo case VNTSD_STATUS_ACQUIRE_WRITER: 178*1ae08745Sheppo rv = acquire_writer(clientp); 179*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 180*1ae08745Sheppo return (rv); 181*1ae08745Sheppo } 182*1ae08745Sheppo break; 183*1ae08745Sheppo default: 184*1ae08745Sheppo return (rv); 185*1ae08745Sheppo } 186*1ae08745Sheppo } 187*1ae08745Sheppo } 188*1ae08745Sheppo 189*1ae08745Sheppo /* vntsd_read worker */ 190*1ae08745Sheppo int 191*1ae08745Sheppo vntsd_read(vntsd_client_t *clientp) 192*1ae08745Sheppo { 193*1ae08745Sheppo char c; 194*1ae08745Sheppo int rv; 195*1ae08745Sheppo 196*1ae08745Sheppo 197*1ae08745Sheppo assert(clientp); 198*1ae08745Sheppo D3(stderr, "t@%d vntsd_read@%d\n", thr_self(), clientp->sockfd); 199*1ae08745Sheppo 200*1ae08745Sheppo for (; ; ) { 201*1ae08745Sheppo 202*1ae08745Sheppo /* client input */ 203*1ae08745Sheppo rv = read_char(clientp, &c); 204*1ae08745Sheppo 205*1ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 206*1ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 207*1ae08745Sheppo } 208*1ae08745Sheppo 209*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 210*1ae08745Sheppo return (rv); 211*1ae08745Sheppo } 212*1ae08745Sheppo 213*1ae08745Sheppo assert(clientp->cons); 214*1ae08745Sheppo if (clientp->cons->clientpq->handle != clientp) { 215*1ae08745Sheppo /* reader - print error message */ 216*1ae08745Sheppo if ((c != CR) && (c != LF)) { 217*1ae08745Sheppo rv = vntsd_write_line(clientp, 218*1ae08745Sheppo gettext(VNTSD_NO_WRITE_ACCESS_MSG)); 219*1ae08745Sheppo 220*1ae08745Sheppo /* check errors and may exit */ 221*1ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 222*1ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 223*1ae08745Sheppo } 224*1ae08745Sheppo 225*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 226*1ae08745Sheppo return (rv); 227*1ae08745Sheppo } 228*1ae08745Sheppo 229*1ae08745Sheppo } 230*1ae08745Sheppo 231*1ae08745Sheppo continue; 232*1ae08745Sheppo } 233*1ae08745Sheppo 234*1ae08745Sheppo rv = vntsd_ctrl_cmd(clientp, c); 235*1ae08745Sheppo 236*1ae08745Sheppo switch (rv) { 237*1ae08745Sheppo case VNTSD_STATUS_CONTINUE: 238*1ae08745Sheppo continue; 239*1ae08745Sheppo break; 240*1ae08745Sheppo case VNTSD_STATUS_INTR: 241*1ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 242*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 243*1ae08745Sheppo return (rv); 244*1ae08745Sheppo } 245*1ae08745Sheppo break; 246*1ae08745Sheppo case VNTSD_SUCCESS: 247*1ae08745Sheppo break; 248*1ae08745Sheppo default: 249*1ae08745Sheppo return (rv); 250*1ae08745Sheppo } 251*1ae08745Sheppo 252*1ae08745Sheppo /* write to vcc */ 253*1ae08745Sheppo rv = write_vcc(clientp, c); 254*1ae08745Sheppo if (rv == VNTSD_STATUS_INTR) { 255*1ae08745Sheppo rv = vntsd_cons_chk_intr(clientp); 256*1ae08745Sheppo } 257*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 258*1ae08745Sheppo return (rv); 259*1ae08745Sheppo } 260*1ae08745Sheppo 261*1ae08745Sheppo } 262*1ae08745Sheppo 263*1ae08745Sheppo /*NOTREACHED*/ 264*1ae08745Sheppo return (NULL); 265*1ae08745Sheppo } 266