11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo /* 221991Sheppo * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 231991Sheppo * Use is subject to license terms. 241991Sheppo */ 251991Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 261991Sheppo 271991Sheppo /* 281991Sheppo * Listen thread creates a console thread whenever there is a tcp client 291991Sheppo * made a conection to its port. In the console thread, if there are 301991Sheppo * multiple consoles in the group, client will be asked for a console selection. 311991Sheppo * a write thread for a console is created when first client connects to a 321991Sheppo * selected console and console thread becomes read thread for the client. 331991Sheppo */ 341991Sheppo 351991Sheppo #include <stdio.h> 361991Sheppo #include <stdlib.h> 371991Sheppo #include <string.h> 381991Sheppo #include <unistd.h> 391991Sheppo #include <sys/types.h> 401991Sheppo #include <sys/socket.h> 411991Sheppo #include <netinet/in.h> 421991Sheppo #include <thread.h> 431991Sheppo #include <synch.h> 441991Sheppo #include <signal.h> 451991Sheppo #include <assert.h> 461991Sheppo #include <ctype.h> 471991Sheppo #include <syslog.h> 481991Sheppo #include <libintl.h> 491991Sheppo #include <netdb.h> 501991Sheppo #include "vntsd.h" 511991Sheppo #include "chars.h" 521991Sheppo 531991Sheppo /* display domain names in the group */ 541991Sheppo static boolean_t 551991Sheppo display_domain_name(vntsd_cons_t *consp, int *fd) 561991Sheppo { 571991Sheppo char buf[VNTSD_LINE_LEN]; 581991Sheppo char *status; 591991Sheppo 601991Sheppo 611991Sheppo if (consp->clientpq != NULL) { 621991Sheppo status = gettext("connected"); 631991Sheppo } else if (consp->status & VNTSD_CONS_DELETED) { 641991Sheppo status = gettext("removing..."); 651991Sheppo } else { 661991Sheppo status = gettext("online"); 671991Sheppo } 681991Sheppo 691991Sheppo (void) snprintf(buf, sizeof (buf), "%-20d%-30s%-25s%s", 701991Sheppo consp->cons_no, consp->domain_name, status, vntsd_eol); 711991Sheppo 721991Sheppo return (vntsd_write_fd(*fd, buf, strlen(buf)) != VNTSD_SUCCESS); 731991Sheppo } 741991Sheppo 751991Sheppo /* output connected message to tcp client */ 761991Sheppo static int 771991Sheppo write_connect_msg(vntsd_client_t *clientp, char *group_name, 781991Sheppo char *domain_name) 791991Sheppo { 801991Sheppo 811991Sheppo int rv = VNTSD_SUCCESS; 821991Sheppo char buf[VNTSD_LINE_LEN]; 831991Sheppo 841991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) != 851991Sheppo VNTSD_SUCCESS) { 861991Sheppo return (rv); 871991Sheppo } 881991Sheppo 891991Sheppo (void) snprintf(buf, sizeof (buf), 901991Sheppo gettext("Connecting to console \"%s\" in group \"%s\" ...."), 911991Sheppo domain_name, group_name); 921991Sheppo 931991Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 941991Sheppo return (rv); 951991Sheppo } 961991Sheppo 971991Sheppo if ((rv = vntsd_write_line(clientp, 981991Sheppo gettext("Press ~? for control options .."))) != 991991Sheppo VNTSD_SUCCESS) { 1001991Sheppo return (rv); 1011991Sheppo } 1021991Sheppo 1031991Sheppo return (VNTSD_SUCCESS); 1041991Sheppo } 1051991Sheppo 1061991Sheppo static int 1071991Sheppo create_write_thread(vntsd_cons_t *consp) 1081991Sheppo { 1091991Sheppo 1101991Sheppo assert(consp); 1111991Sheppo 1121991Sheppo /* create write thread for the console */ 1131991Sheppo (void) mutex_lock(&consp->lock); 1141991Sheppo if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread, 1151991Sheppo (void *)consp, NULL, &consp->wr_tid)) { 1161991Sheppo 1171991Sheppo DERR(stderr, "t@%d create_rd_wr_thread@%d: " 1181991Sheppo "create write thread failed\n", 1191991Sheppo thr_self(), consp->cons_no); 1201991Sheppo (void) close(consp->vcc_fd); 1211991Sheppo consp->vcc_fd = -1; 1221991Sheppo (void) mutex_unlock(&consp->lock); 1231991Sheppo 1241991Sheppo return (VNTSD_ERR_CREATE_WR_THR); 1251991Sheppo } 1261991Sheppo (void) mutex_unlock(&consp->lock); 1271991Sheppo return (VNTSD_SUCCESS); 1281991Sheppo } 1291991Sheppo 1301991Sheppo /* Display all domain consoles in a group. */ 1311991Sheppo static int 1321991Sheppo list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp) 1331991Sheppo { 1341991Sheppo char vntsd_line[VNTSD_LINE_LEN]; 1351991Sheppo int rv = VNTSD_SUCCESS; 1361991Sheppo 1371991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1381991Sheppo != VNTSD_SUCCESS) { 1391991Sheppo return (rv); 1401991Sheppo } 1411991Sheppo 1421991Sheppo /* 1431991Sheppo * TRANSLATION_NOTE 1441991Sheppo * The following three strings of the form "DOMAIN .." are table 1451991Sheppo * headers and should be all uppercase. 1461991Sheppo */ 1471991Sheppo (void) snprintf(vntsd_line, sizeof (vntsd_line), 1481991Sheppo "%-20s%-30s%-25s", 1491991Sheppo gettext("DOMAIN ID"), gettext("DOMAIN NAME"), 1501991Sheppo gettext("DOMAIN STATE")); 1511991Sheppo 1521991Sheppo if ((rv = vntsd_write_line(clientp, vntsd_line)) != VNTSD_SUCCESS) { 1531991Sheppo return (rv); 1541991Sheppo } 1551991Sheppo 1561991Sheppo (void) mutex_lock(&groupp->lock); 1571991Sheppo 1581991Sheppo if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name, 1591991Sheppo &(clientp->sockfd)) != NULL) { 1601991Sheppo rv = VNTSD_ERR_WRITE_CLIENT; 1611991Sheppo } 1621991Sheppo 1631991Sheppo (void) mutex_unlock(&groupp->lock); 1641991Sheppo 1651991Sheppo return (rv); 1661991Sheppo } 1671991Sheppo 1681991Sheppo /* display help */ 1691991Sheppo static int 1701991Sheppo display_help(vntsd_client_t *clientp) 1711991Sheppo { 1721991Sheppo int rv = VNTSD_SUCCESS; 1731991Sheppo char *bufp; 1741991Sheppo 1751991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1761991Sheppo != VNTSD_SUCCESS) { 1771991Sheppo return (rv); 1781991Sheppo } 1791991Sheppo 1801991Sheppo /* 1811991Sheppo * TRANSLATION_NOTE 1821991Sheppo * The following three strings of the form ". -- ..." are help 1831991Sheppo * messages for single character commands. Do not translate the 1841991Sheppo * character before the --. 1851991Sheppo */ 1862109Slm66018 bufp = gettext("h -- this help"); 1871991Sheppo 1881991Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 1891991Sheppo return (rv); 1901991Sheppo } 1911991Sheppo 1921991Sheppo bufp = gettext("l -- list of consoles"); 1931991Sheppo 1941991Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 1951991Sheppo return (rv); 1961991Sheppo } 1971991Sheppo 1981991Sheppo bufp = gettext("q -- quit"); 1991991Sheppo 2001991Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 2011991Sheppo return (rv); 2021991Sheppo } 2031991Sheppo 2041991Sheppo /* 2051991Sheppo * TRANSLATION_NOTE 2061991Sheppo * In the following string, "id" is a short mnemonic for 2071991Sheppo * "identifier" and both occurrences should be translated. 2081991Sheppo */ 2091991Sheppo 2102109Slm66018 bufp = gettext("c{id}, n{name} -- connect to a console of domain {id}" 2112109Slm66018 " or domain {name}"); 2121991Sheppo 2131991Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 2141991Sheppo return (rv); 2151991Sheppo } 2161991Sheppo 2171991Sheppo return (VNTSD_SUCCESS); 2181991Sheppo } 2191991Sheppo 2202109Slm66018 /* cons_by_name() - find a console structure according to a ldom's name */ 2212109Slm66018 static boolean_t 2222109Slm66018 cons_by_name(vntsd_cons_t *consp, char *name) 2232109Slm66018 { 2242109Slm66018 if (consp->status & VNTSD_CONS_DELETED) { 2252109Slm66018 return (B_FALSE); 2262109Slm66018 } 2272109Slm66018 return (strcmp(consp->domain_name, name) == 0); 2282109Slm66018 } 2292109Slm66018 2302109Slm66018 /* name_to_cons_no - convert a ldom's name to its consno */ 2312109Slm66018 static int 2322109Slm66018 name_to_cons_no(vntsd_group_t *groupp, char *name) 2332109Slm66018 { 2342109Slm66018 vntsd_cons_t *consp; 2352109Slm66018 2362109Slm66018 consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq, 2372109Slm66018 (compare_func_t)cons_by_name, name); 2382109Slm66018 2392109Slm66018 if (consp == NULL) { 2402109Slm66018 return (-1); 2412109Slm66018 } 2422109Slm66018 2432109Slm66018 return (consp->cons_no); 2442109Slm66018 } 2452109Slm66018 2461991Sheppo /* select a console to connect */ 2471991Sheppo static int 2482109Slm66018 select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp, 2491991Sheppo vntsd_client_t *clientp, char c) 2501991Sheppo { 2512109Slm66018 int cons_no = -1; 2521991Sheppo int n; 2531991Sheppo int i; 2541991Sheppo char buf[VNTSD_LINE_LEN]; 2551991Sheppo int rv; 2561991Sheppo 2571991Sheppo 2581991Sheppo 2591991Sheppo (void) mutex_lock(&groupp->lock); 2601991Sheppo if (groupp->num_cons == 0) { 2611991Sheppo (void) mutex_unlock(&groupp->lock); 2621991Sheppo /* no console in this group */ 2631991Sheppo return (VNTSD_STATUS_NO_CONS); 2641991Sheppo } 2651991Sheppo (void) mutex_unlock(&groupp->lock); 2661991Sheppo 2671991Sheppo 2682109Slm66018 /* c{id} or n{name} */ 2691991Sheppo 2701991Sheppo n = VNTSD_LINE_LEN; 2711991Sheppo 2721991Sheppo if ((rv = vntsd_read_line(clientp, buf, &n)) != VNTSD_SUCCESS) { 2731991Sheppo return (rv); 2741991Sheppo } 2751991Sheppo 2761991Sheppo /* parse command */ 2771991Sheppo for (i = 0; i < n; i++) { 2782109Slm66018 switch (c) { 2792109Slm66018 2802109Slm66018 case 'c': 2812109Slm66018 /* c{id} or c {id} */ 2822109Slm66018 if (isspace(buf[i])) { 2832109Slm66018 continue; 2842109Slm66018 } 2852109Slm66018 2862109Slm66018 if (!isdigit(buf[i])) { 2872109Slm66018 return (VNTSD_ERR_INVALID_INPUT); 2882109Slm66018 } 2892109Slm66018 2901991Sheppo cons_no = atoi(buf + i); 2911991Sheppo break; 2922109Slm66018 2932109Slm66018 case 'n': 2942109Slm66018 /* n{name) or n {name} */ 2952109Slm66018 if (isspace(buf[i])) { 2962109Slm66018 continue; 2972109Slm66018 } 2982109Slm66018 2992109Slm66018 buf[n-1] = 0; 3002109Slm66018 cons_no = name_to_cons_no(groupp, buf+i); 3012109Slm66018 break; 3022109Slm66018 3032109Slm66018 default: 3042109Slm66018 /* should never get here */ 3052109Slm66018 return (VNTSD_ERR_INVALID_INPUT); 3062109Slm66018 3071991Sheppo } 3081991Sheppo 3092109Slm66018 /* got user selection */ 3102109Slm66018 break; 3111991Sheppo } 3121991Sheppo 3131991Sheppo if (cons_no < 0) { 3141991Sheppo return (VNTSD_ERR_INVALID_INPUT); 3151991Sheppo } 3161991Sheppo 3171991Sheppo /* get selected console */ 3181991Sheppo (void) mutex_lock(&groupp->lock); 3191991Sheppo 3201991Sheppo *consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq, 3211991Sheppo (compare_func_t)vntsd_cons_by_consno, &cons_no); 3221991Sheppo 3231991Sheppo if (*consp == NULL) { 3241991Sheppo /* during console selection, the console has been deleted */ 3251991Sheppo (void) mutex_unlock(&groupp->lock); 3261991Sheppo 3271991Sheppo return (VNTSD_ERR_INVALID_INPUT); 3281991Sheppo } 3291991Sheppo if ((*consp)->status & VNTSD_CONS_DELETED) { 3301991Sheppo return (VNTSD_ERR_INVALID_INPUT); 3311991Sheppo } 3321991Sheppo 3331991Sheppo (void) mutex_unlock(&groupp->lock); 3341991Sheppo 3351991Sheppo return (VNTSD_SUCCESS); 3361991Sheppo } 3371991Sheppo 3381991Sheppo /* compare if there is a match console in the gorup */ 3391991Sheppo static boolean_t 3401991Sheppo find_cons_in_group(vntsd_cons_t *consp_in_group, vntsd_cons_t *consp) 3411991Sheppo { 3421991Sheppo if (consp_in_group == consp) { 3431991Sheppo return (B_TRUE); 3441991Sheppo } else { 3451991Sheppo return (B_FALSE); 3461991Sheppo } 3471991Sheppo } 3481991Sheppo 3491991Sheppo /* connect a client to a console */ 3501991Sheppo static int 3511991Sheppo connect_cons(vntsd_cons_t *consp, vntsd_client_t *clientp) 3521991Sheppo { 3531991Sheppo int rv, rv1; 3541991Sheppo vntsd_group_t *groupp; 3551991Sheppo 3561991Sheppo assert(consp); 3571991Sheppo groupp = consp->group; 3581991Sheppo assert(groupp); 3591991Sheppo assert(clientp); 3601991Sheppo 3611991Sheppo (void) mutex_lock(&groupp->lock); 3621991Sheppo 3631991Sheppo /* check if console is valid */ 3641991Sheppo consp = vntsd_que_find(groupp->conspq, 3651991Sheppo (compare_func_t)find_cons_in_group, consp); 3661991Sheppo 3671991Sheppo if (consp == NULL) { 3681991Sheppo (void) mutex_unlock(&groupp->lock); 3691991Sheppo return (VNTSD_STATUS_NO_CONS); 3701991Sheppo } 3711991Sheppo if (consp->status & VNTSD_CONS_DELETED) { 3721991Sheppo (void) mutex_unlock(&groupp->lock); 3731991Sheppo return (VNTSD_STATUS_NO_CONS); 3741991Sheppo } 3751991Sheppo 3761991Sheppo (void) mutex_lock(&consp->lock); 3771991Sheppo (void) mutex_lock(&clientp->lock); 3781991Sheppo 3791991Sheppo 3801991Sheppo clientp->cons = consp; 3811991Sheppo 3821991Sheppo /* enable daemon cmd */ 3831991Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 3841991Sheppo 3852748Slm66018 if (consp->clientpq == NULL && consp->vcc_fd == -1) { 3862748Slm66018 3872748Slm66018 /* 3882748Slm66018 * the first connection to a console - a writer 3892748Slm66018 * and the console has not opened. 3902748Slm66018 */ 3911991Sheppo consp->vcc_fd = vntsd_open_vcc(consp->dev_name, consp->cons_no); 3921991Sheppo if (consp->vcc_fd < 0) { 3931991Sheppo (void) mutex_unlock(&clientp->lock); 3941991Sheppo (void) mutex_unlock(&consp->lock); 3951991Sheppo (void) mutex_unlock(&groupp->lock); 3961991Sheppo assert(consp->group); 3971991Sheppo return (vntsd_vcc_err(consp)); 3981991Sheppo } 3991991Sheppo } 4001991Sheppo 4011991Sheppo (void) mutex_unlock(&clientp->lock); 4021991Sheppo 4031991Sheppo /* 4041991Sheppo * move the client from group's no console selected queue 4051991Sheppo * to cons queue 4061991Sheppo */ 4071991Sheppo 4081991Sheppo rv = vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 4091991Sheppo assert(rv == VNTSD_SUCCESS); 4101991Sheppo 4111991Sheppo rv = vntsd_que_append(&consp->clientpq, clientp); 4121991Sheppo (void) mutex_unlock(&groupp->lock); 4131991Sheppo 4141991Sheppo if (rv != VNTSD_SUCCESS) { 4151991Sheppo if (consp->clientpq->handle == clientp) { 4161991Sheppo /* writer */ 4171991Sheppo (void) close(consp->vcc_fd); 4181991Sheppo consp->vcc_fd = -1; 4191991Sheppo } 4201991Sheppo 4211991Sheppo (void) mutex_unlock(&consp->lock); 4221991Sheppo return (rv); 4231991Sheppo } 4241991Sheppo 4251991Sheppo (void) mutex_unlock(&consp->lock); 4261991Sheppo 4271991Sheppo if (consp->clientpq->handle == clientp) { 4281991Sheppo /* create a write thread */ 4291991Sheppo rv = create_write_thread(consp); 4301991Sheppo if (rv != VNTSD_SUCCESS) { 4311991Sheppo return (rv); 4321991Sheppo } 4331991Sheppo } 4341991Sheppo 4351991Sheppo /* write connecting message */ 4361991Sheppo if ((rv = write_connect_msg(clientp, consp->group->group_name, 4371991Sheppo consp->domain_name)) != VNTSD_SUCCESS) { 4381991Sheppo return (rv); 4391991Sheppo } 4401991Sheppo 4411991Sheppo /* process input from client */ 4421991Sheppo rv = vntsd_read(clientp); 4431991Sheppo 4441991Sheppo /* client disconnected from the console */ 4451991Sheppo (void) mutex_lock(&groupp->lock); 4461991Sheppo 4471991Sheppo /* remove client from console queue */ 4481991Sheppo (void) mutex_lock(&consp->lock); 4491991Sheppo rv1 = vntsd_que_rm(&consp->clientpq, clientp); 4501991Sheppo assert(rv1 == VNTSD_SUCCESS); 4511991Sheppo 4521991Sheppo /* append client to group's no console selected queue */ 4531991Sheppo rv1 = vntsd_que_append(&groupp->no_cons_clientpq, clientp); 4541991Sheppo (void) mutex_unlock(&groupp->lock); 4551991Sheppo 4561991Sheppo if (consp->clientpq == NULL) { 4571991Sheppo /* clean up console since there is no client connected to it */ 4581991Sheppo assert(consp->vcc_fd != -1); 4591991Sheppo 4601991Sheppo /* force write thread to exit */ 4611991Sheppo assert(consp->wr_tid != (thread_t)-1); 4621991Sheppo (void) thr_kill(consp->wr_tid, SIGUSR1); 4631991Sheppo (void) mutex_unlock(&consp->lock); 4641991Sheppo (void) thr_join(consp->wr_tid, NULL, NULL); 4651991Sheppo (void) mutex_lock(&consp->lock); 4661991Sheppo } 4671991Sheppo 4681991Sheppo if (consp->status & VNTSD_CONS_SIG_WAIT) { 4691991Sheppo /* console is waiting for client to disconnect */ 4701991Sheppo (void) cond_signal(&consp->cvp); 4711991Sheppo } 4721991Sheppo 4731991Sheppo (void) mutex_unlock(&consp->lock); 4741991Sheppo 4751991Sheppo return (rv1 == VNTSD_SUCCESS ? rv : rv1); 4761991Sheppo 4771991Sheppo } 4781991Sheppo 4791991Sheppo /* read command line input */ 4801991Sheppo static int 4811991Sheppo read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd) 4821991Sheppo { 4831991Sheppo int rv; 4841991Sheppo 4851991Sheppo /* disable daemon special command */ 4861991Sheppo (void) mutex_lock(&clientp->lock); 4871991Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 4881991Sheppo (void) mutex_unlock(&clientp->lock); 4891991Sheppo 4901991Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 4911991Sheppo != VNTSD_SUCCESS) { 4921991Sheppo return (rv); 4931991Sheppo } 4941991Sheppo 4951991Sheppo if ((rv = vntsd_write_client(clientp, prompt, strlen(prompt))) 4961991Sheppo != VNTSD_SUCCESS) { 4971991Sheppo return (rv); 4981991Sheppo } 4991991Sheppo 5001991Sheppo if ((rv = vntsd_read_data(clientp, cmd)) != VNTSD_SUCCESS) { 5011991Sheppo return (rv); 5021991Sheppo } 5031991Sheppo if (*cmd == BS) { 5041991Sheppo return (VNTSD_SUCCESS); 5051991Sheppo } 5061991Sheppo 5071991Sheppo rv = vntsd_write_client(clientp, cmd, 1); 5081991Sheppo 5091991Sheppo *cmd = tolower(*cmd); 5101991Sheppo 5111991Sheppo return (rv); 5121991Sheppo } 5131991Sheppo 5141991Sheppo /* reset client for selecting a console in the group */ 5151991Sheppo static void 5161991Sheppo client_init(vntsd_client_t *clientp) 5171991Sheppo { 5181991Sheppo (void) mutex_lock(&clientp->lock); 5191991Sheppo clientp->cons = NULL; 5201991Sheppo clientp->status = 0; 5211991Sheppo (void) mutex_unlock(&clientp->lock); 5221991Sheppo } 5232748Slm66018 /* is there any connection to a given console? */ 5242748Slm66018 static boolean_t 5252748Slm66018 is_client_que_empty(vntsd_cons_t *consp) 5262748Slm66018 { 5272748Slm66018 boolean_t has_client = B_FALSE; 5282748Slm66018 5292748Slm66018 (void) mutex_lock(&consp->lock); 5302748Slm66018 5312748Slm66018 if (consp->clientpq != NULL) 5322748Slm66018 has_client = B_TRUE; 5332748Slm66018 5342748Slm66018 (void) mutex_unlock(&consp->lock); 5352748Slm66018 5362748Slm66018 return (has_client); 5372748Slm66018 } 5382748Slm66018 5392748Slm66018 /* 5402748Slm66018 * close one opened console. 5412748Slm66018 * This function is passed to vntsd_que_walk to close one console. 5422748Slm66018 * The function returns B_FALSE so that vntsd_que_walk will 5432748Slm66018 * continue to apply the function to all consoles in the group. 5442748Slm66018 */ 5452748Slm66018 static boolean_t 5462748Slm66018 close_one_vcc_fd(vntsd_cons_t *consp) 5472748Slm66018 { 5482748Slm66018 (void) mutex_lock(&consp->lock); 5492748Slm66018 5502748Slm66018 if (consp->vcc_fd != -1) { 5512748Slm66018 (void) close(consp->vcc_fd); 5522748Slm66018 consp->vcc_fd = -1; 5532748Slm66018 } 5542748Slm66018 5552748Slm66018 (void) mutex_unlock(&consp->lock); 5562748Slm66018 5572748Slm66018 return (B_FALSE); 5582748Slm66018 } 5592748Slm66018 5601991Sheppo 5611991Sheppo /* clean up client and exit the thread */ 5621991Sheppo static void 5631991Sheppo client_fini(vntsd_group_t *groupp, vntsd_client_t *clientp) 5641991Sheppo { 5651991Sheppo 5661991Sheppo assert(groupp); 5671991Sheppo assert(clientp); 5681991Sheppo 5691991Sheppo /* disconnct client from tcp port */ 5701991Sheppo assert(clientp->sockfd != -1); 5711991Sheppo (void) close(clientp->sockfd); 5721991Sheppo 5731991Sheppo (void) mutex_lock(&groupp->lock); 5742748Slm66018 5752748Slm66018 /* 5762748Slm66018 * close all consoles in the group if the client is the 5772748Slm66018 * last one connected to the group 5782748Slm66018 */ 5792748Slm66018 if (vntsd_que_walk(groupp->conspq, (el_func_t)is_client_que_empty) == 5802748Slm66018 VNTSD_SUCCESS) { 5812748Slm66018 (void) vntsd_que_walk(groupp->conspq, 5822748Slm66018 (el_func_t)close_one_vcc_fd); 5832748Slm66018 } 5842748Slm66018 5852748Slm66018 5861991Sheppo (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 5871991Sheppo 5881991Sheppo if ((groupp->no_cons_clientpq == NULL) && 5891991Sheppo (groupp->status & VNTSD_GROUP_SIG_WAIT)) { 590*3151Ssg70180 /* 591*3151Ssg70180 * group is waiting to be deleted. - signal the group's 592*3151Ssg70180 * listen thread - the VNTSD_GROUP_SIG_WAIT state will 593*3151Ssg70180 * be cleared when the listen thread exits. 594*3151Ssg70180 */ 5951991Sheppo (void) cond_signal(&groupp->cvp); 5961991Sheppo } 5971991Sheppo (void) mutex_unlock(&groupp->lock); 5981991Sheppo 5991991Sheppo (void) mutex_destroy(&clientp->lock); 6001991Sheppo free(clientp); 6011991Sheppo 6021991Sheppo thr_exit(0); 6031991Sheppo } 6041991Sheppo 6051991Sheppo /* check client's status. exit if client quits or fatal errors */ 6061991Sheppo static void 6071991Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status) 6081991Sheppo { 6091991Sheppo char err_msg[VNTSD_LINE_LEN]; 6101991Sheppo 6111991Sheppo D1(stderr, "t@%d console_chk_status() status=%d " 6121991Sheppo "client status=%x num consoles=%d \n", 6131991Sheppo thr_self(), status, clientp->status, groupp->num_cons); 6141991Sheppo 6151991Sheppo (void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d" 6161991Sheppo " num_cos=%d", clientp->sockfd, groupp->num_cons); 6171991Sheppo 618*3151Ssg70180 /* 619*3151Ssg70180 * obtain group lock to protect groupp->num_cons. 620*3151Ssg70180 * When groupp->num_cons == 0, close client and exit the tread. 621*3151Ssg70180 */ 622*3151Ssg70180 (void) mutex_lock(&groupp->lock); 623*3151Ssg70180 6241991Sheppo if (groupp->num_cons == 0) { 6251991Sheppo /* no more console in the group */ 626*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6271991Sheppo client_fini(groupp, clientp); 628*3151Ssg70180 return; 6291991Sheppo } 6301991Sheppo 6311991Sheppo if (status == VNTSD_STATUS_INTR) { 6321991Sheppo /* reason for signal? */ 6331991Sheppo status = vntsd_cons_chk_intr(clientp); 6341991Sheppo } 6351991Sheppo 6361991Sheppo switch (status) { 6371991Sheppo 6381991Sheppo case VNTSD_STATUS_CLIENT_QUIT: 639*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6401991Sheppo client_fini(groupp, clientp); 6411991Sheppo return; 6421991Sheppo 6431991Sheppo case VNTSD_STATUS_RESELECT_CONS: 644*3151Ssg70180 645*3151Ssg70180 if (clientp->cons == NULL) { 646*3151Ssg70180 /* 647*3151Ssg70180 * domain was deleted before client connects to it 648*3151Ssg70180 * connect to other console in the same group 649*3151Ssg70180 */ 650*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 651*3151Ssg70180 client_init(clientp); 652*3151Ssg70180 return; 653*3151Ssg70180 } 654*3151Ssg70180 6551991Sheppo if ((groupp->num_cons == 1) && 656*3151Ssg70180 ((clientp->status & VNTSD_CLIENT_CONS_DELETED) || 657*3151Ssg70180 (groupp->conspq->handle == clientp->cons))) { 6581991Sheppo /* no other selection available */ 659*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6601991Sheppo client_fini(groupp, clientp); 6611991Sheppo } else { 662*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6631991Sheppo client_init(clientp); 6641991Sheppo } 665*3151Ssg70180 6661991Sheppo return; 6671991Sheppo 6681991Sheppo case VNTSD_STATUS_VCC_IO_ERR: 6691991Sheppo if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) { 6701991Sheppo /* check if console was deleted */ 671*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6721991Sheppo status = vntsd_vcc_err(clientp->cons); 673*3151Ssg70180 (void) mutex_lock(&groupp->lock); 6741991Sheppo } 6751991Sheppo 6761991Sheppo if (status != VNTSD_STATUS_CONTINUE) { 6771991Sheppo /* console was deleted */ 678*3151Ssg70180 if (groupp->num_cons <= 1) { 679*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6801991Sheppo client_fini(groupp, clientp); 681*3151Ssg70180 return; 6821991Sheppo } 6831991Sheppo } 6841991Sheppo 685*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6861991Sheppo /* console is ok */ 6871991Sheppo client_init(clientp); 6881991Sheppo return; 6891991Sheppo 6901991Sheppo case VNTSD_STATUS_MOV_CONS_FORWARD: 6911991Sheppo case VNTSD_STATUS_MOV_CONS_BACKWARD: 6921991Sheppo if (groupp->num_cons == 1) { 6931991Sheppo /* same console */ 694*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 6951991Sheppo return; 6961991Sheppo } 6971991Sheppo 6981991Sheppo /* get selected console */ 699*3151Ssg70180 clientp->cons = vntsd_que_pos(groupp->conspq, 7001991Sheppo clientp->cons, 7011991Sheppo (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1)); 702*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 7031991Sheppo return; 7041991Sheppo 7051991Sheppo case VNTSD_SUCCESS: 7061991Sheppo case VNTSD_STATUS_CONTINUE: 7071991Sheppo case VNTSD_STATUS_NO_CONS: 708*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 7091991Sheppo client_init(clientp); 7101991Sheppo return; 7111991Sheppo 7121991Sheppo case VNTSD_ERR_INVALID_INPUT: 713*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 7141991Sheppo return; 7151991Sheppo 7161991Sheppo default: 7171991Sheppo /* fatal error */ 718*3151Ssg70180 (void) mutex_unlock(&groupp->lock); 7191991Sheppo vntsd_log(status, err_msg); 7201991Sheppo client_fini(groupp, clientp); 7211991Sheppo return; 7221991Sheppo } 7231991Sheppo } 7241991Sheppo 7251991Sheppo /* console thread */ 7261991Sheppo void * 7271991Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp) 7281991Sheppo { 7291991Sheppo vntsd_group_t *groupp; 7301991Sheppo vntsd_cons_t *consp; 7311991Sheppo vntsd_client_t *clientp; 7321991Sheppo 7331991Sheppo char buf[MAXHOSTNAMELEN]; 7341991Sheppo char prompt[72]; 7351991Sheppo char cmd; 7361991Sheppo int rv = VNTSD_SUCCESS; 7371991Sheppo int num_cons; 7381991Sheppo 7391991Sheppo 7401991Sheppo groupp = (vntsd_group_t *)argp->handle; 7411991Sheppo clientp = (vntsd_client_t *)argp->arg; 7421991Sheppo 7431991Sheppo assert(groupp); 7441991Sheppo assert(clientp); 7451991Sheppo 7461991Sheppo /* check if group is removed */ 7471991Sheppo 7481991Sheppo D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(), 7491991Sheppo groupp->tcp_port, clientp->sockfd); 7501991Sheppo 7511991Sheppo bzero(buf, MAXHOSTNAMELEN); 7521991Sheppo 7531991Sheppo /* host name */ 7541991Sheppo if (gethostname(buf, MAXHOSTNAMELEN)) { 7551991Sheppo vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()"); 7561991Sheppo (void) snprintf(buf, sizeof (buf), "unkown host"); 7571991Sheppo } 7581991Sheppo 7591991Sheppo if (snprintf(prompt, sizeof (prompt), 7602109Slm66018 "%s-vnts-%s: h, l, c{id}, n{name}, q:", 7611991Sheppo buf, groupp->group_name) >= sizeof (prompt)) { 7621991Sheppo /* long prompt doesn't fit, use short one */ 7631991Sheppo (void) snprintf(prompt, sizeof (prompt), 7642109Slm66018 "vnts: h, l, c{id}, n{name}, q:"); 7651991Sheppo } 7661991Sheppo 7671991Sheppo 7681991Sheppo for (;;) { 7691991Sheppo cmd = ' '; 7701991Sheppo D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(), 7711991Sheppo groupp->tcp_port, clientp->sockfd); 7721991Sheppo 7731991Sheppo num_cons = vntsd_chk_group_total_cons(groupp); 7741991Sheppo 7751991Sheppo if ((num_cons > 1) && (clientp->cons == NULL)) { 7761991Sheppo /* console to connect to */ 7771991Sheppo rv = read_cmd(clientp, prompt, &cmd); 7781991Sheppo /* check error and may exit */ 7791991Sheppo console_chk_status(groupp, clientp, rv); 780*3151Ssg70180 781*3151Ssg70180 /* any console is removed from group? */ 782*3151Ssg70180 num_cons = vntsd_chk_group_total_cons(groupp); 783*3151Ssg70180 if (num_cons <= 1) { 784*3151Ssg70180 cmd = ' '; 785*3151Ssg70180 } 7861991Sheppo } 7871991Sheppo 7881991Sheppo switch (cmd) { 7891991Sheppo 7901991Sheppo case 'l': 7911991Sheppo 7921991Sheppo /* list domain names */ 7931991Sheppo rv = list_all_domains(groupp, clientp); 7941991Sheppo break; 7951991Sheppo 7961991Sheppo 7971991Sheppo case 'q': 7981991Sheppo 7991991Sheppo rv = VNTSD_STATUS_CLIENT_QUIT; 8001991Sheppo break; 8011991Sheppo 8022109Slm66018 case ' ': 8032109Slm66018 804*3151Ssg70180 if (num_cons == 0) 805*3151Ssg70180 /* no console in the group */ 806*3151Ssg70180 break; 807*3151Ssg70180 8082109Slm66018 if (clientp->cons == NULL) { 8092109Slm66018 if (num_cons == 1) { 8102109Slm66018 /* by pass selecting console */ 8112109Slm66018 consp = (vntsd_cons_t *) 8122109Slm66018 (groupp->conspq->handle); 8132109Slm66018 } else { 8142109Slm66018 continue; 8152109Slm66018 } 8162109Slm66018 8172109Slm66018 } else { 8182109Slm66018 consp = clientp->cons; 8192109Slm66018 } 8202109Slm66018 8212109Slm66018 /* connect to console */ 8222109Slm66018 rv = connect_cons(consp, clientp); 8232109Slm66018 8241991Sheppo break; 8251991Sheppo 8262109Slm66018 case 'c': 8272109Slm66018 case 'n': 8281991Sheppo /* select console */ 8291991Sheppo if (clientp->cons == NULL) { 8302109Slm66018 rv = select_cons(groupp, &consp, clientp, cmd); 8311991Sheppo if (rv == VNTSD_ERR_INVALID_INPUT) { 8321991Sheppo rv = display_help(clientp); 8331991Sheppo break; 8341991Sheppo } 8351991Sheppo } else { 8361991Sheppo consp = clientp->cons; 8371991Sheppo } 8381991Sheppo assert(consp); 8391991Sheppo 8401991Sheppo /* connect to console */ 8411991Sheppo rv = connect_cons(consp, clientp); 8421991Sheppo D1(stderr, "t@%d console_thread()" 8431991Sheppo "connect_cons returns %d\n", 8441991Sheppo thr_self(), rv); 8451991Sheppo break; 8461991Sheppo 8472109Slm66018 case 'h': 8482109Slm66018 default: 8492109Slm66018 rv = display_help(clientp); 8502109Slm66018 break; 8512109Slm66018 8521991Sheppo } 8532109Slm66018 8541991Sheppo /* check error and may exit */ 8551991Sheppo console_chk_status(groupp, clientp, rv); 8561991Sheppo } 8571991Sheppo 8581991Sheppo /*NOTREACHED*/ 8591991Sheppo return (NULL); 8601991Sheppo } 861