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 #pragma ident "%Z%%M% %I% %E% SMI" 26*1ae08745Sheppo 27*1ae08745Sheppo /* 28*1ae08745Sheppo * Listen thread creates a console thread whenever there is a tcp client 29*1ae08745Sheppo * made a conection to its port. In the console thread, if there are 30*1ae08745Sheppo * multiple consoles in the group, client will be asked for a console selection. 31*1ae08745Sheppo * a write thread for a console is created when first client connects to a 32*1ae08745Sheppo * selected console and console thread becomes read thread for the client. 33*1ae08745Sheppo */ 34*1ae08745Sheppo 35*1ae08745Sheppo #include <stdio.h> 36*1ae08745Sheppo #include <stdlib.h> 37*1ae08745Sheppo #include <string.h> 38*1ae08745Sheppo #include <unistd.h> 39*1ae08745Sheppo #include <sys/types.h> 40*1ae08745Sheppo #include <sys/socket.h> 41*1ae08745Sheppo #include <netinet/in.h> 42*1ae08745Sheppo #include <thread.h> 43*1ae08745Sheppo #include <synch.h> 44*1ae08745Sheppo #include <signal.h> 45*1ae08745Sheppo #include <assert.h> 46*1ae08745Sheppo #include <ctype.h> 47*1ae08745Sheppo #include <syslog.h> 48*1ae08745Sheppo #include <libintl.h> 49*1ae08745Sheppo #include <netdb.h> 50*1ae08745Sheppo #include "vntsd.h" 51*1ae08745Sheppo #include "chars.h" 52*1ae08745Sheppo 53*1ae08745Sheppo /* display domain names in the group */ 54*1ae08745Sheppo static boolean_t 55*1ae08745Sheppo display_domain_name(vntsd_cons_t *consp, int *fd) 56*1ae08745Sheppo { 57*1ae08745Sheppo char buf[VNTSD_LINE_LEN]; 58*1ae08745Sheppo char *status; 59*1ae08745Sheppo 60*1ae08745Sheppo 61*1ae08745Sheppo if (consp->clientpq != NULL) { 62*1ae08745Sheppo status = gettext("connected"); 63*1ae08745Sheppo } else if (consp->status & VNTSD_CONS_DELETED) { 64*1ae08745Sheppo status = gettext("removing..."); 65*1ae08745Sheppo } else { 66*1ae08745Sheppo status = gettext("online"); 67*1ae08745Sheppo } 68*1ae08745Sheppo 69*1ae08745Sheppo (void) snprintf(buf, sizeof (buf), "%-20d%-30s%-25s%s", 70*1ae08745Sheppo consp->cons_no, consp->domain_name, status, vntsd_eol); 71*1ae08745Sheppo 72*1ae08745Sheppo return (vntsd_write_fd(*fd, buf, strlen(buf)) != VNTSD_SUCCESS); 73*1ae08745Sheppo } 74*1ae08745Sheppo 75*1ae08745Sheppo /* output connected message to tcp client */ 76*1ae08745Sheppo static int 77*1ae08745Sheppo write_connect_msg(vntsd_client_t *clientp, char *group_name, 78*1ae08745Sheppo char *domain_name) 79*1ae08745Sheppo { 80*1ae08745Sheppo 81*1ae08745Sheppo int rv = VNTSD_SUCCESS; 82*1ae08745Sheppo char buf[VNTSD_LINE_LEN]; 83*1ae08745Sheppo 84*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) != 85*1ae08745Sheppo VNTSD_SUCCESS) { 86*1ae08745Sheppo return (rv); 87*1ae08745Sheppo } 88*1ae08745Sheppo 89*1ae08745Sheppo (void) snprintf(buf, sizeof (buf), 90*1ae08745Sheppo gettext("Connecting to console \"%s\" in group \"%s\" ...."), 91*1ae08745Sheppo domain_name, group_name); 92*1ae08745Sheppo 93*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 94*1ae08745Sheppo return (rv); 95*1ae08745Sheppo } 96*1ae08745Sheppo 97*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, 98*1ae08745Sheppo gettext("Press ~? for control options .."))) != 99*1ae08745Sheppo VNTSD_SUCCESS) { 100*1ae08745Sheppo return (rv); 101*1ae08745Sheppo } 102*1ae08745Sheppo 103*1ae08745Sheppo return (VNTSD_SUCCESS); 104*1ae08745Sheppo } 105*1ae08745Sheppo 106*1ae08745Sheppo static int 107*1ae08745Sheppo create_write_thread(vntsd_cons_t *consp) 108*1ae08745Sheppo { 109*1ae08745Sheppo 110*1ae08745Sheppo assert(consp); 111*1ae08745Sheppo 112*1ae08745Sheppo /* create write thread for the console */ 113*1ae08745Sheppo (void) mutex_lock(&consp->lock); 114*1ae08745Sheppo if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread, 115*1ae08745Sheppo (void *)consp, NULL, &consp->wr_tid)) { 116*1ae08745Sheppo 117*1ae08745Sheppo DERR(stderr, "t@%d create_rd_wr_thread@%d: " 118*1ae08745Sheppo "create write thread failed\n", 119*1ae08745Sheppo thr_self(), consp->cons_no); 120*1ae08745Sheppo (void) close(consp->vcc_fd); 121*1ae08745Sheppo consp->vcc_fd = -1; 122*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 123*1ae08745Sheppo 124*1ae08745Sheppo return (VNTSD_ERR_CREATE_WR_THR); 125*1ae08745Sheppo } 126*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 127*1ae08745Sheppo return (VNTSD_SUCCESS); 128*1ae08745Sheppo } 129*1ae08745Sheppo 130*1ae08745Sheppo /* Display all domain consoles in a group. */ 131*1ae08745Sheppo static int 132*1ae08745Sheppo list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp) 133*1ae08745Sheppo { 134*1ae08745Sheppo char vntsd_line[VNTSD_LINE_LEN]; 135*1ae08745Sheppo int rv = VNTSD_SUCCESS; 136*1ae08745Sheppo 137*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 138*1ae08745Sheppo != VNTSD_SUCCESS) { 139*1ae08745Sheppo return (rv); 140*1ae08745Sheppo } 141*1ae08745Sheppo 142*1ae08745Sheppo /* 143*1ae08745Sheppo * TRANSLATION_NOTE 144*1ae08745Sheppo * The following three strings of the form "DOMAIN .." are table 145*1ae08745Sheppo * headers and should be all uppercase. 146*1ae08745Sheppo */ 147*1ae08745Sheppo (void) snprintf(vntsd_line, sizeof (vntsd_line), 148*1ae08745Sheppo "%-20s%-30s%-25s", 149*1ae08745Sheppo gettext("DOMAIN ID"), gettext("DOMAIN NAME"), 150*1ae08745Sheppo gettext("DOMAIN STATE")); 151*1ae08745Sheppo 152*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, vntsd_line)) != VNTSD_SUCCESS) { 153*1ae08745Sheppo return (rv); 154*1ae08745Sheppo } 155*1ae08745Sheppo 156*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 157*1ae08745Sheppo 158*1ae08745Sheppo if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name, 159*1ae08745Sheppo &(clientp->sockfd)) != NULL) { 160*1ae08745Sheppo rv = VNTSD_ERR_WRITE_CLIENT; 161*1ae08745Sheppo } 162*1ae08745Sheppo 163*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 164*1ae08745Sheppo 165*1ae08745Sheppo return (rv); 166*1ae08745Sheppo } 167*1ae08745Sheppo 168*1ae08745Sheppo /* display help */ 169*1ae08745Sheppo static int 170*1ae08745Sheppo display_help(vntsd_client_t *clientp) 171*1ae08745Sheppo { 172*1ae08745Sheppo int rv = VNTSD_SUCCESS; 173*1ae08745Sheppo char *bufp; 174*1ae08745Sheppo 175*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 176*1ae08745Sheppo != VNTSD_SUCCESS) { 177*1ae08745Sheppo return (rv); 178*1ae08745Sheppo } 179*1ae08745Sheppo 180*1ae08745Sheppo /* 181*1ae08745Sheppo * TRANSLATION_NOTE 182*1ae08745Sheppo * The following three strings of the form ". -- ..." are help 183*1ae08745Sheppo * messages for single character commands. Do not translate the 184*1ae08745Sheppo * character before the --. 185*1ae08745Sheppo */ 186*1ae08745Sheppo bufp = gettext("h -- this help)"); 187*1ae08745Sheppo 188*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 189*1ae08745Sheppo return (rv); 190*1ae08745Sheppo } 191*1ae08745Sheppo 192*1ae08745Sheppo bufp = gettext("l -- list of consoles"); 193*1ae08745Sheppo 194*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 195*1ae08745Sheppo return (rv); 196*1ae08745Sheppo } 197*1ae08745Sheppo 198*1ae08745Sheppo bufp = gettext("q -- quit"); 199*1ae08745Sheppo 200*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 201*1ae08745Sheppo return (rv); 202*1ae08745Sheppo } 203*1ae08745Sheppo 204*1ae08745Sheppo /* 205*1ae08745Sheppo * TRANSLATION_NOTE 206*1ae08745Sheppo * In the following string, "id" is a short mnemonic for 207*1ae08745Sheppo * "identifier" and both occurrences should be translated. 208*1ae08745Sheppo */ 209*1ae08745Sheppo 210*1ae08745Sheppo bufp = gettext("[c[c ]]{id} -- connect to console of domain {id}"); 211*1ae08745Sheppo 212*1ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 213*1ae08745Sheppo return (rv); 214*1ae08745Sheppo } 215*1ae08745Sheppo 216*1ae08745Sheppo return (VNTSD_SUCCESS); 217*1ae08745Sheppo } 218*1ae08745Sheppo 219*1ae08745Sheppo /* select a console to connect */ 220*1ae08745Sheppo static int 221*1ae08745Sheppo select_cons(vntsd_group_t *groupp, int num_cons, vntsd_cons_t **consp, 222*1ae08745Sheppo vntsd_client_t *clientp, char c) 223*1ae08745Sheppo { 224*1ae08745Sheppo int cons_no = -2; 225*1ae08745Sheppo int n; 226*1ae08745Sheppo int i; 227*1ae08745Sheppo char buf[VNTSD_LINE_LEN]; 228*1ae08745Sheppo int rv; 229*1ae08745Sheppo 230*1ae08745Sheppo 231*1ae08745Sheppo 232*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 233*1ae08745Sheppo if (groupp->num_cons == 0) { 234*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 235*1ae08745Sheppo /* no console in this group */ 236*1ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 237*1ae08745Sheppo } 238*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 239*1ae08745Sheppo 240*1ae08745Sheppo if (num_cons == 1) { 241*1ae08745Sheppo /* by pass selecting console */ 242*1ae08745Sheppo *consp = (vntsd_cons_t *)(groupp->conspq->handle); 243*1ae08745Sheppo return (VNTSD_SUCCESS); 244*1ae08745Sheppo } 245*1ae08745Sheppo 246*1ae08745Sheppo 247*1ae08745Sheppo if (isdigit(c)) { 248*1ae08745Sheppo /* {id} input */ 249*1ae08745Sheppo cons_no = c - '0'; 250*1ae08745Sheppo } else if (c == 'c') { 251*1ae08745Sheppo /* c{id} or c {id} input */ 252*1ae08745Sheppo cons_no = -1; 253*1ae08745Sheppo } else if (!isspace(c)) { 254*1ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 255*1ae08745Sheppo } 256*1ae08745Sheppo 257*1ae08745Sheppo /* get client selections */ 258*1ae08745Sheppo n = VNTSD_LINE_LEN; 259*1ae08745Sheppo 260*1ae08745Sheppo if ((rv = vntsd_read_line(clientp, buf, &n)) != VNTSD_SUCCESS) { 261*1ae08745Sheppo return (rv); 262*1ae08745Sheppo } 263*1ae08745Sheppo 264*1ae08745Sheppo /* parse command */ 265*1ae08745Sheppo for (i = 0; i < n; i++) { 266*1ae08745Sheppo if (cons_no == -1) { 267*1ae08745Sheppo /* c{id} */ 268*1ae08745Sheppo cons_no = atoi(buf + i); 269*1ae08745Sheppo break; 270*1ae08745Sheppo } 271*1ae08745Sheppo 272*1ae08745Sheppo if (isspace(buf[i]) && cons_no == -2) { 273*1ae08745Sheppo /* skip space */ 274*1ae08745Sheppo continue; 275*1ae08745Sheppo } 276*1ae08745Sheppo 277*1ae08745Sheppo if (buf[i] == 'c') { 278*1ae08745Sheppo /* c{id} or c {id} */ 279*1ae08745Sheppo cons_no = -1; 280*1ae08745Sheppo } else if (buf[i] == CR) { 281*1ae08745Sheppo break; 282*1ae08745Sheppo } else { 283*1ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 284*1ae08745Sheppo } 285*1ae08745Sheppo } 286*1ae08745Sheppo 287*1ae08745Sheppo if (cons_no < 0) { 288*1ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 289*1ae08745Sheppo } 290*1ae08745Sheppo 291*1ae08745Sheppo /* get selected console */ 292*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 293*1ae08745Sheppo 294*1ae08745Sheppo *consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq, 295*1ae08745Sheppo (compare_func_t)vntsd_cons_by_consno, &cons_no); 296*1ae08745Sheppo 297*1ae08745Sheppo if (*consp == NULL) { 298*1ae08745Sheppo /* during console selection, the console has been deleted */ 299*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 300*1ae08745Sheppo 301*1ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 302*1ae08745Sheppo } 303*1ae08745Sheppo if ((*consp)->status & VNTSD_CONS_DELETED) { 304*1ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 305*1ae08745Sheppo } 306*1ae08745Sheppo 307*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 308*1ae08745Sheppo 309*1ae08745Sheppo return (VNTSD_SUCCESS); 310*1ae08745Sheppo } 311*1ae08745Sheppo 312*1ae08745Sheppo /* compare if there is a match console in the gorup */ 313*1ae08745Sheppo static boolean_t 314*1ae08745Sheppo find_cons_in_group(vntsd_cons_t *consp_in_group, vntsd_cons_t *consp) 315*1ae08745Sheppo { 316*1ae08745Sheppo if (consp_in_group == consp) { 317*1ae08745Sheppo return (B_TRUE); 318*1ae08745Sheppo } else { 319*1ae08745Sheppo return (B_FALSE); 320*1ae08745Sheppo } 321*1ae08745Sheppo } 322*1ae08745Sheppo 323*1ae08745Sheppo /* connect a client to a console */ 324*1ae08745Sheppo static int 325*1ae08745Sheppo connect_cons(vntsd_cons_t *consp, vntsd_client_t *clientp) 326*1ae08745Sheppo { 327*1ae08745Sheppo int rv, rv1; 328*1ae08745Sheppo vntsd_group_t *groupp; 329*1ae08745Sheppo 330*1ae08745Sheppo assert(consp); 331*1ae08745Sheppo groupp = consp->group; 332*1ae08745Sheppo assert(groupp); 333*1ae08745Sheppo assert(clientp); 334*1ae08745Sheppo 335*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 336*1ae08745Sheppo 337*1ae08745Sheppo /* check if console is valid */ 338*1ae08745Sheppo consp = vntsd_que_find(groupp->conspq, 339*1ae08745Sheppo (compare_func_t)find_cons_in_group, consp); 340*1ae08745Sheppo 341*1ae08745Sheppo if (consp == NULL) { 342*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 343*1ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 344*1ae08745Sheppo } 345*1ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 346*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 347*1ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 348*1ae08745Sheppo } 349*1ae08745Sheppo 350*1ae08745Sheppo (void) mutex_lock(&consp->lock); 351*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 352*1ae08745Sheppo 353*1ae08745Sheppo 354*1ae08745Sheppo clientp->cons = consp; 355*1ae08745Sheppo 356*1ae08745Sheppo /* enable daemon cmd */ 357*1ae08745Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 358*1ae08745Sheppo 359*1ae08745Sheppo if (consp->clientpq == NULL) { 360*1ae08745Sheppo /* first connect to console - a writer */ 361*1ae08745Sheppo assert(consp->vcc_fd == -1); 362*1ae08745Sheppo /* open vcc */ 363*1ae08745Sheppo consp->vcc_fd = vntsd_open_vcc(consp->dev_name, consp->cons_no); 364*1ae08745Sheppo if (consp->vcc_fd < 0) { 365*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 366*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 367*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 368*1ae08745Sheppo assert(consp->group); 369*1ae08745Sheppo return (vntsd_vcc_err(consp)); 370*1ae08745Sheppo } 371*1ae08745Sheppo } 372*1ae08745Sheppo 373*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 374*1ae08745Sheppo 375*1ae08745Sheppo /* 376*1ae08745Sheppo * move the client from group's no console selected queue 377*1ae08745Sheppo * to cons queue 378*1ae08745Sheppo */ 379*1ae08745Sheppo 380*1ae08745Sheppo rv = vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 381*1ae08745Sheppo assert(rv == VNTSD_SUCCESS); 382*1ae08745Sheppo 383*1ae08745Sheppo rv = vntsd_que_append(&consp->clientpq, clientp); 384*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 385*1ae08745Sheppo 386*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 387*1ae08745Sheppo if (consp->clientpq->handle == clientp) { 388*1ae08745Sheppo /* writer */ 389*1ae08745Sheppo (void) close(consp->vcc_fd); 390*1ae08745Sheppo consp->vcc_fd = -1; 391*1ae08745Sheppo } 392*1ae08745Sheppo 393*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 394*1ae08745Sheppo return (rv); 395*1ae08745Sheppo } 396*1ae08745Sheppo 397*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 398*1ae08745Sheppo 399*1ae08745Sheppo if (consp->clientpq->handle == clientp) { 400*1ae08745Sheppo /* create a write thread */ 401*1ae08745Sheppo rv = create_write_thread(consp); 402*1ae08745Sheppo if (rv != VNTSD_SUCCESS) { 403*1ae08745Sheppo return (rv); 404*1ae08745Sheppo } 405*1ae08745Sheppo } 406*1ae08745Sheppo 407*1ae08745Sheppo /* write connecting message */ 408*1ae08745Sheppo if ((rv = write_connect_msg(clientp, consp->group->group_name, 409*1ae08745Sheppo consp->domain_name)) != VNTSD_SUCCESS) { 410*1ae08745Sheppo return (rv); 411*1ae08745Sheppo } 412*1ae08745Sheppo 413*1ae08745Sheppo /* process input from client */ 414*1ae08745Sheppo rv = vntsd_read(clientp); 415*1ae08745Sheppo 416*1ae08745Sheppo /* client disconnected from the console */ 417*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 418*1ae08745Sheppo 419*1ae08745Sheppo /* remove client from console queue */ 420*1ae08745Sheppo (void) mutex_lock(&consp->lock); 421*1ae08745Sheppo rv1 = vntsd_que_rm(&consp->clientpq, clientp); 422*1ae08745Sheppo assert(rv1 == VNTSD_SUCCESS); 423*1ae08745Sheppo 424*1ae08745Sheppo /* append client to group's no console selected queue */ 425*1ae08745Sheppo rv1 = vntsd_que_append(&groupp->no_cons_clientpq, clientp); 426*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 427*1ae08745Sheppo 428*1ae08745Sheppo if (consp->clientpq == NULL) { 429*1ae08745Sheppo /* clean up console since there is no client connected to it */ 430*1ae08745Sheppo assert(consp->vcc_fd != -1); 431*1ae08745Sheppo 432*1ae08745Sheppo /* close vcc port */ 433*1ae08745Sheppo (void) close(consp->vcc_fd); 434*1ae08745Sheppo consp->vcc_fd = -1; 435*1ae08745Sheppo 436*1ae08745Sheppo /* force write thread to exit */ 437*1ae08745Sheppo assert(consp->wr_tid != (thread_t)-1); 438*1ae08745Sheppo (void) thr_kill(consp->wr_tid, SIGUSR1); 439*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 440*1ae08745Sheppo (void) thr_join(consp->wr_tid, NULL, NULL); 441*1ae08745Sheppo (void) mutex_lock(&consp->lock); 442*1ae08745Sheppo } 443*1ae08745Sheppo 444*1ae08745Sheppo if (consp->status & VNTSD_CONS_SIG_WAIT) { 445*1ae08745Sheppo /* console is waiting for client to disconnect */ 446*1ae08745Sheppo (void) cond_signal(&consp->cvp); 447*1ae08745Sheppo } 448*1ae08745Sheppo 449*1ae08745Sheppo (void) mutex_unlock(&consp->lock); 450*1ae08745Sheppo 451*1ae08745Sheppo return (rv1 == VNTSD_SUCCESS ? rv : rv1); 452*1ae08745Sheppo 453*1ae08745Sheppo } 454*1ae08745Sheppo 455*1ae08745Sheppo /* read command line input */ 456*1ae08745Sheppo static int 457*1ae08745Sheppo read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd) 458*1ae08745Sheppo { 459*1ae08745Sheppo int rv; 460*1ae08745Sheppo 461*1ae08745Sheppo /* disable daemon special command */ 462*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 463*1ae08745Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 464*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 465*1ae08745Sheppo 466*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 467*1ae08745Sheppo != VNTSD_SUCCESS) { 468*1ae08745Sheppo return (rv); 469*1ae08745Sheppo } 470*1ae08745Sheppo 471*1ae08745Sheppo if ((rv = vntsd_write_client(clientp, prompt, strlen(prompt))) 472*1ae08745Sheppo != VNTSD_SUCCESS) { 473*1ae08745Sheppo return (rv); 474*1ae08745Sheppo } 475*1ae08745Sheppo 476*1ae08745Sheppo if ((rv = vntsd_read_data(clientp, cmd)) != VNTSD_SUCCESS) { 477*1ae08745Sheppo return (rv); 478*1ae08745Sheppo } 479*1ae08745Sheppo if (*cmd == BS) { 480*1ae08745Sheppo return (VNTSD_SUCCESS); 481*1ae08745Sheppo } 482*1ae08745Sheppo 483*1ae08745Sheppo rv = vntsd_write_client(clientp, cmd, 1); 484*1ae08745Sheppo 485*1ae08745Sheppo *cmd = tolower(*cmd); 486*1ae08745Sheppo 487*1ae08745Sheppo return (rv); 488*1ae08745Sheppo } 489*1ae08745Sheppo 490*1ae08745Sheppo /* reset client for selecting a console in the group */ 491*1ae08745Sheppo static void 492*1ae08745Sheppo client_init(vntsd_client_t *clientp) 493*1ae08745Sheppo { 494*1ae08745Sheppo (void) mutex_lock(&clientp->lock); 495*1ae08745Sheppo clientp->cons = NULL; 496*1ae08745Sheppo clientp->status = 0; 497*1ae08745Sheppo (void) mutex_unlock(&clientp->lock); 498*1ae08745Sheppo } 499*1ae08745Sheppo 500*1ae08745Sheppo /* clean up client and exit the thread */ 501*1ae08745Sheppo static void 502*1ae08745Sheppo client_fini(vntsd_group_t *groupp, vntsd_client_t *clientp) 503*1ae08745Sheppo { 504*1ae08745Sheppo 505*1ae08745Sheppo assert(groupp); 506*1ae08745Sheppo assert(clientp); 507*1ae08745Sheppo 508*1ae08745Sheppo /* disconnct client from tcp port */ 509*1ae08745Sheppo assert(clientp->sockfd != -1); 510*1ae08745Sheppo (void) close(clientp->sockfd); 511*1ae08745Sheppo 512*1ae08745Sheppo (void) mutex_lock(&groupp->lock); 513*1ae08745Sheppo (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 514*1ae08745Sheppo 515*1ae08745Sheppo if ((groupp->no_cons_clientpq == NULL) && 516*1ae08745Sheppo (groupp->status & VNTSD_GROUP_SIG_WAIT)) { 517*1ae08745Sheppo /* group is waiting to be deleted */ 518*1ae08745Sheppo groupp->status &= ~VNTSD_GROUP_SIG_WAIT; 519*1ae08745Sheppo (void) cond_signal(&groupp->cvp); 520*1ae08745Sheppo } 521*1ae08745Sheppo (void) mutex_unlock(&groupp->lock); 522*1ae08745Sheppo 523*1ae08745Sheppo (void) mutex_destroy(&clientp->lock); 524*1ae08745Sheppo free(clientp); 525*1ae08745Sheppo 526*1ae08745Sheppo thr_exit(0); 527*1ae08745Sheppo } 528*1ae08745Sheppo 529*1ae08745Sheppo /* check client's status. exit if client quits or fatal errors */ 530*1ae08745Sheppo static void 531*1ae08745Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status) 532*1ae08745Sheppo { 533*1ae08745Sheppo char err_msg[VNTSD_LINE_LEN]; 534*1ae08745Sheppo 535*1ae08745Sheppo D1(stderr, "t@%d console_chk_status() status=%d " 536*1ae08745Sheppo "client status=%x num consoles=%d \n", 537*1ae08745Sheppo thr_self(), status, clientp->status, groupp->num_cons); 538*1ae08745Sheppo 539*1ae08745Sheppo (void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d" 540*1ae08745Sheppo " num_cos=%d", clientp->sockfd, groupp->num_cons); 541*1ae08745Sheppo 542*1ae08745Sheppo if (groupp->num_cons == 0) { 543*1ae08745Sheppo /* no more console in the group */ 544*1ae08745Sheppo client_fini(groupp, clientp); 545*1ae08745Sheppo } 546*1ae08745Sheppo 547*1ae08745Sheppo if (status == VNTSD_STATUS_INTR) { 548*1ae08745Sheppo /* reason for signal? */ 549*1ae08745Sheppo status = vntsd_cons_chk_intr(clientp); 550*1ae08745Sheppo } 551*1ae08745Sheppo 552*1ae08745Sheppo switch (status) { 553*1ae08745Sheppo 554*1ae08745Sheppo case VNTSD_STATUS_CLIENT_QUIT: 555*1ae08745Sheppo client_fini(groupp, clientp); 556*1ae08745Sheppo return; 557*1ae08745Sheppo 558*1ae08745Sheppo case VNTSD_STATUS_RESELECT_CONS: 559*1ae08745Sheppo assert(clientp->cons); 560*1ae08745Sheppo if ((groupp->num_cons == 1) && 561*1ae08745Sheppo (groupp->conspq->handle == clientp->cons)) { 562*1ae08745Sheppo /* no other selection available */ 563*1ae08745Sheppo client_fini(groupp, clientp); 564*1ae08745Sheppo } else { 565*1ae08745Sheppo client_init(clientp); 566*1ae08745Sheppo } 567*1ae08745Sheppo return; 568*1ae08745Sheppo 569*1ae08745Sheppo case VNTSD_STATUS_VCC_IO_ERR: 570*1ae08745Sheppo if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) { 571*1ae08745Sheppo /* check if console was deleted */ 572*1ae08745Sheppo status = vntsd_vcc_err(clientp->cons); 573*1ae08745Sheppo } 574*1ae08745Sheppo 575*1ae08745Sheppo if (status != VNTSD_STATUS_CONTINUE) { 576*1ae08745Sheppo /* console was deleted */ 577*1ae08745Sheppo if (groupp->num_cons == 1) { 578*1ae08745Sheppo client_fini(groupp, clientp); 579*1ae08745Sheppo } 580*1ae08745Sheppo } 581*1ae08745Sheppo 582*1ae08745Sheppo /* console is ok */ 583*1ae08745Sheppo client_init(clientp); 584*1ae08745Sheppo return; 585*1ae08745Sheppo 586*1ae08745Sheppo case VNTSD_STATUS_MOV_CONS_FORWARD: 587*1ae08745Sheppo case VNTSD_STATUS_MOV_CONS_BACKWARD: 588*1ae08745Sheppo if (groupp->num_cons == 1) { 589*1ae08745Sheppo /* same console */ 590*1ae08745Sheppo return; 591*1ae08745Sheppo } 592*1ae08745Sheppo 593*1ae08745Sheppo /* get selected console */ 594*1ae08745Sheppo (void) mutex_lock(&(clientp->cons->group->lock)); 595*1ae08745Sheppo clientp->cons = vntsd_que_pos(clientp->cons->group->conspq, 596*1ae08745Sheppo clientp->cons, 597*1ae08745Sheppo (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1)); 598*1ae08745Sheppo (void) mutex_unlock(&(clientp->cons->group->lock)); 599*1ae08745Sheppo return; 600*1ae08745Sheppo 601*1ae08745Sheppo case VNTSD_SUCCESS: 602*1ae08745Sheppo case VNTSD_STATUS_CONTINUE: 603*1ae08745Sheppo case VNTSD_STATUS_NO_CONS: 604*1ae08745Sheppo client_init(clientp); 605*1ae08745Sheppo return; 606*1ae08745Sheppo 607*1ae08745Sheppo case VNTSD_ERR_INVALID_INPUT: 608*1ae08745Sheppo return; 609*1ae08745Sheppo 610*1ae08745Sheppo default: 611*1ae08745Sheppo /* fatal error */ 612*1ae08745Sheppo vntsd_log(status, err_msg); 613*1ae08745Sheppo client_fini(groupp, clientp); 614*1ae08745Sheppo return; 615*1ae08745Sheppo } 616*1ae08745Sheppo } 617*1ae08745Sheppo 618*1ae08745Sheppo /* console thread */ 619*1ae08745Sheppo void * 620*1ae08745Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp) 621*1ae08745Sheppo { 622*1ae08745Sheppo vntsd_group_t *groupp; 623*1ae08745Sheppo vntsd_cons_t *consp; 624*1ae08745Sheppo vntsd_client_t *clientp; 625*1ae08745Sheppo 626*1ae08745Sheppo char buf[MAXHOSTNAMELEN]; 627*1ae08745Sheppo char prompt[72]; 628*1ae08745Sheppo char cmd; 629*1ae08745Sheppo int rv = VNTSD_SUCCESS; 630*1ae08745Sheppo int num_cons; 631*1ae08745Sheppo 632*1ae08745Sheppo 633*1ae08745Sheppo groupp = (vntsd_group_t *)argp->handle; 634*1ae08745Sheppo clientp = (vntsd_client_t *)argp->arg; 635*1ae08745Sheppo 636*1ae08745Sheppo assert(groupp); 637*1ae08745Sheppo assert(clientp); 638*1ae08745Sheppo 639*1ae08745Sheppo /* check if group is removed */ 640*1ae08745Sheppo 641*1ae08745Sheppo D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(), 642*1ae08745Sheppo groupp->tcp_port, clientp->sockfd); 643*1ae08745Sheppo 644*1ae08745Sheppo bzero(buf, MAXHOSTNAMELEN); 645*1ae08745Sheppo 646*1ae08745Sheppo /* host name */ 647*1ae08745Sheppo if (gethostname(buf, MAXHOSTNAMELEN)) { 648*1ae08745Sheppo vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()"); 649*1ae08745Sheppo (void) snprintf(buf, sizeof (buf), "unkown host"); 650*1ae08745Sheppo } 651*1ae08745Sheppo 652*1ae08745Sheppo if (snprintf(prompt, sizeof (prompt), 653*1ae08745Sheppo "%s-vnts-%s: h,l,{id},c{id},c {id},q:", 654*1ae08745Sheppo buf, groupp->group_name) >= sizeof (prompt)) { 655*1ae08745Sheppo /* long prompt doesn't fit, use short one */ 656*1ae08745Sheppo (void) snprintf(prompt, sizeof (prompt), 657*1ae08745Sheppo "vnts: h,l,{id},c{id},c {id}, q:"); 658*1ae08745Sheppo } 659*1ae08745Sheppo 660*1ae08745Sheppo 661*1ae08745Sheppo for (;;) { 662*1ae08745Sheppo cmd = ' '; 663*1ae08745Sheppo D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(), 664*1ae08745Sheppo groupp->tcp_port, clientp->sockfd); 665*1ae08745Sheppo 666*1ae08745Sheppo num_cons = vntsd_chk_group_total_cons(groupp); 667*1ae08745Sheppo 668*1ae08745Sheppo if ((num_cons > 1) && (clientp->cons == NULL)) { 669*1ae08745Sheppo /* console to connect to */ 670*1ae08745Sheppo rv = read_cmd(clientp, prompt, &cmd); 671*1ae08745Sheppo /* check error and may exit */ 672*1ae08745Sheppo console_chk_status(groupp, clientp, rv); 673*1ae08745Sheppo } 674*1ae08745Sheppo 675*1ae08745Sheppo switch (cmd) { 676*1ae08745Sheppo 677*1ae08745Sheppo case 'l': 678*1ae08745Sheppo 679*1ae08745Sheppo /* list domain names */ 680*1ae08745Sheppo rv = list_all_domains(groupp, clientp); 681*1ae08745Sheppo break; 682*1ae08745Sheppo 683*1ae08745Sheppo 684*1ae08745Sheppo case 'q': 685*1ae08745Sheppo 686*1ae08745Sheppo rv = VNTSD_STATUS_CLIENT_QUIT; 687*1ae08745Sheppo break; 688*1ae08745Sheppo 689*1ae08745Sheppo case 'h': 690*1ae08745Sheppo rv = display_help(clientp); 691*1ae08745Sheppo break; 692*1ae08745Sheppo 693*1ae08745Sheppo default: 694*1ae08745Sheppo /* select console */ 695*1ae08745Sheppo if (clientp->cons == NULL) { 696*1ae08745Sheppo rv = select_cons(groupp, num_cons, 697*1ae08745Sheppo &consp, clientp, cmd); 698*1ae08745Sheppo if (rv == VNTSD_ERR_INVALID_INPUT) { 699*1ae08745Sheppo rv = display_help(clientp); 700*1ae08745Sheppo break; 701*1ae08745Sheppo } 702*1ae08745Sheppo } else { 703*1ae08745Sheppo consp = clientp->cons; 704*1ae08745Sheppo } 705*1ae08745Sheppo assert(consp); 706*1ae08745Sheppo 707*1ae08745Sheppo /* connect to console */ 708*1ae08745Sheppo rv = connect_cons(consp, clientp); 709*1ae08745Sheppo D1(stderr, "t@%d console_thread()" 710*1ae08745Sheppo "connect_cons returns %d\n", 711*1ae08745Sheppo thr_self(), rv); 712*1ae08745Sheppo break; 713*1ae08745Sheppo 714*1ae08745Sheppo } 715*1ae08745Sheppo /* check error and may exit */ 716*1ae08745Sheppo console_chk_status(groupp, clientp, rv); 717*1ae08745Sheppo } 718*1ae08745Sheppo 719*1ae08745Sheppo /*NOTREACHED*/ 720*1ae08745Sheppo return (NULL); 721*1ae08745Sheppo } 722