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 /* 22*3c96341aSnarayan * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 231ae08745Sheppo * Use is subject to license terms. 241ae08745Sheppo */ 251ae08745Sheppo #pragma ident "%Z%%M% %I% %E% SMI" 261ae08745Sheppo 271ae08745Sheppo /* 281ae08745Sheppo * Listen thread creates a console thread whenever there is a tcp client 291ae08745Sheppo * made a conection to its port. In the console thread, if there are 301ae08745Sheppo * multiple consoles in the group, client will be asked for a console selection. 311ae08745Sheppo * a write thread for a console is created when first client connects to a 321ae08745Sheppo * selected console and console thread becomes read thread for the client. 331ae08745Sheppo */ 341ae08745Sheppo 351ae08745Sheppo #include <stdio.h> 361ae08745Sheppo #include <stdlib.h> 371ae08745Sheppo #include <string.h> 381ae08745Sheppo #include <unistd.h> 391ae08745Sheppo #include <sys/types.h> 401ae08745Sheppo #include <sys/socket.h> 411ae08745Sheppo #include <netinet/in.h> 421ae08745Sheppo #include <thread.h> 431ae08745Sheppo #include <synch.h> 441ae08745Sheppo #include <signal.h> 451ae08745Sheppo #include <assert.h> 461ae08745Sheppo #include <ctype.h> 471ae08745Sheppo #include <syslog.h> 481ae08745Sheppo #include <libintl.h> 491ae08745Sheppo #include <netdb.h> 501ae08745Sheppo #include "vntsd.h" 511ae08745Sheppo #include "chars.h" 521ae08745Sheppo 531ae08745Sheppo /* display domain names in the group */ 541ae08745Sheppo static boolean_t 551ae08745Sheppo display_domain_name(vntsd_cons_t *consp, int *fd) 561ae08745Sheppo { 571ae08745Sheppo char buf[VNTSD_LINE_LEN]; 581ae08745Sheppo char *status; 591ae08745Sheppo 601ae08745Sheppo 611ae08745Sheppo if (consp->clientpq != NULL) { 621ae08745Sheppo status = gettext("connected"); 631ae08745Sheppo } else if (consp->status & VNTSD_CONS_DELETED) { 641ae08745Sheppo status = gettext("removing..."); 651ae08745Sheppo } else { 661ae08745Sheppo status = gettext("online"); 671ae08745Sheppo } 681ae08745Sheppo 691ae08745Sheppo (void) snprintf(buf, sizeof (buf), "%-20d%-30s%-25s%s", 701ae08745Sheppo consp->cons_no, consp->domain_name, status, vntsd_eol); 711ae08745Sheppo 721ae08745Sheppo return (vntsd_write_fd(*fd, buf, strlen(buf)) != VNTSD_SUCCESS); 731ae08745Sheppo } 741ae08745Sheppo 751ae08745Sheppo /* output connected message to tcp client */ 761ae08745Sheppo static int 771ae08745Sheppo write_connect_msg(vntsd_client_t *clientp, char *group_name, 781ae08745Sheppo char *domain_name) 791ae08745Sheppo { 801ae08745Sheppo 811ae08745Sheppo int rv = VNTSD_SUCCESS; 821ae08745Sheppo char buf[VNTSD_LINE_LEN]; 831ae08745Sheppo 841ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) != 851ae08745Sheppo VNTSD_SUCCESS) { 861ae08745Sheppo return (rv); 871ae08745Sheppo } 881ae08745Sheppo 891ae08745Sheppo (void) snprintf(buf, sizeof (buf), 901ae08745Sheppo gettext("Connecting to console \"%s\" in group \"%s\" ...."), 911ae08745Sheppo domain_name, group_name); 921ae08745Sheppo 931ae08745Sheppo if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) { 941ae08745Sheppo return (rv); 951ae08745Sheppo } 961ae08745Sheppo 971ae08745Sheppo if ((rv = vntsd_write_line(clientp, 981ae08745Sheppo gettext("Press ~? for control options .."))) != 991ae08745Sheppo VNTSD_SUCCESS) { 1001ae08745Sheppo return (rv); 1011ae08745Sheppo } 1021ae08745Sheppo 1031ae08745Sheppo return (VNTSD_SUCCESS); 1041ae08745Sheppo } 1051ae08745Sheppo 1061ae08745Sheppo static int 1071ae08745Sheppo create_write_thread(vntsd_cons_t *consp) 1081ae08745Sheppo { 1091ae08745Sheppo 1101ae08745Sheppo assert(consp); 1111ae08745Sheppo 1121ae08745Sheppo /* create write thread for the console */ 1131ae08745Sheppo (void) mutex_lock(&consp->lock); 1141ae08745Sheppo if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread, 1151ae08745Sheppo (void *)consp, NULL, &consp->wr_tid)) { 1161ae08745Sheppo 1171ae08745Sheppo DERR(stderr, "t@%d create_rd_wr_thread@%d: " 1181ae08745Sheppo "create write thread failed\n", 1191ae08745Sheppo thr_self(), consp->cons_no); 1201ae08745Sheppo (void) close(consp->vcc_fd); 1211ae08745Sheppo consp->vcc_fd = -1; 1221ae08745Sheppo (void) mutex_unlock(&consp->lock); 1231ae08745Sheppo 1241ae08745Sheppo return (VNTSD_ERR_CREATE_WR_THR); 1251ae08745Sheppo } 1261ae08745Sheppo (void) mutex_unlock(&consp->lock); 1271ae08745Sheppo return (VNTSD_SUCCESS); 1281ae08745Sheppo } 1291ae08745Sheppo 1301ae08745Sheppo /* Display all domain consoles in a group. */ 1311ae08745Sheppo static int 1321ae08745Sheppo list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp) 1331ae08745Sheppo { 1341ae08745Sheppo char vntsd_line[VNTSD_LINE_LEN]; 1351ae08745Sheppo int rv = VNTSD_SUCCESS; 1361ae08745Sheppo 1371ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1381ae08745Sheppo != VNTSD_SUCCESS) { 1391ae08745Sheppo return (rv); 1401ae08745Sheppo } 1411ae08745Sheppo 1421ae08745Sheppo /* 1431ae08745Sheppo * TRANSLATION_NOTE 1441ae08745Sheppo * The following three strings of the form "DOMAIN .." are table 1451ae08745Sheppo * headers and should be all uppercase. 1461ae08745Sheppo */ 1471ae08745Sheppo (void) snprintf(vntsd_line, sizeof (vntsd_line), 1481ae08745Sheppo "%-20s%-30s%-25s", 1491ae08745Sheppo gettext("DOMAIN ID"), gettext("DOMAIN NAME"), 1501ae08745Sheppo gettext("DOMAIN STATE")); 1511ae08745Sheppo 1521ae08745Sheppo if ((rv = vntsd_write_line(clientp, vntsd_line)) != VNTSD_SUCCESS) { 1531ae08745Sheppo return (rv); 1541ae08745Sheppo } 1551ae08745Sheppo 1561ae08745Sheppo (void) mutex_lock(&groupp->lock); 1571ae08745Sheppo 1581ae08745Sheppo if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name, 1591ae08745Sheppo &(clientp->sockfd)) != NULL) { 1601ae08745Sheppo rv = VNTSD_ERR_WRITE_CLIENT; 1611ae08745Sheppo } 1621ae08745Sheppo 1631ae08745Sheppo (void) mutex_unlock(&groupp->lock); 1641ae08745Sheppo 1651ae08745Sheppo return (rv); 1661ae08745Sheppo } 1671ae08745Sheppo 1681ae08745Sheppo /* display help */ 1691ae08745Sheppo static int 1701ae08745Sheppo display_help(vntsd_client_t *clientp) 1711ae08745Sheppo { 1721ae08745Sheppo int rv = VNTSD_SUCCESS; 1731ae08745Sheppo char *bufp; 1741ae08745Sheppo 1751ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 1761ae08745Sheppo != VNTSD_SUCCESS) { 1771ae08745Sheppo return (rv); 1781ae08745Sheppo } 1791ae08745Sheppo 1801ae08745Sheppo /* 1811ae08745Sheppo * TRANSLATION_NOTE 1821ae08745Sheppo * The following three strings of the form ". -- ..." are help 1831ae08745Sheppo * messages for single character commands. Do not translate the 1841ae08745Sheppo * character before the --. 1851ae08745Sheppo */ 1868e6a2a04Slm66018 bufp = gettext("h -- this help"); 1871ae08745Sheppo 1881ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 1891ae08745Sheppo return (rv); 1901ae08745Sheppo } 1911ae08745Sheppo 1921ae08745Sheppo bufp = gettext("l -- list of consoles"); 1931ae08745Sheppo 1941ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 1951ae08745Sheppo return (rv); 1961ae08745Sheppo } 1971ae08745Sheppo 1981ae08745Sheppo bufp = gettext("q -- quit"); 1991ae08745Sheppo 2001ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 2011ae08745Sheppo return (rv); 2021ae08745Sheppo } 2031ae08745Sheppo 2041ae08745Sheppo /* 2051ae08745Sheppo * TRANSLATION_NOTE 2061ae08745Sheppo * In the following string, "id" is a short mnemonic for 2071ae08745Sheppo * "identifier" and both occurrences should be translated. 2081ae08745Sheppo */ 2091ae08745Sheppo 2108e6a2a04Slm66018 bufp = gettext("c{id}, n{name} -- connect to a console of domain {id}" 2118e6a2a04Slm66018 " or domain {name}"); 2121ae08745Sheppo 2131ae08745Sheppo if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) { 2141ae08745Sheppo return (rv); 2151ae08745Sheppo } 2161ae08745Sheppo 2171ae08745Sheppo return (VNTSD_SUCCESS); 2181ae08745Sheppo } 2191ae08745Sheppo 2208e6a2a04Slm66018 /* cons_by_name() - find a console structure according to a ldom's name */ 2218e6a2a04Slm66018 static boolean_t 2228e6a2a04Slm66018 cons_by_name(vntsd_cons_t *consp, char *name) 2238e6a2a04Slm66018 { 2248e6a2a04Slm66018 if (consp->status & VNTSD_CONS_DELETED) { 2258e6a2a04Slm66018 return (B_FALSE); 2268e6a2a04Slm66018 } 2278e6a2a04Slm66018 return (strcmp(consp->domain_name, name) == 0); 2288e6a2a04Slm66018 } 2298e6a2a04Slm66018 2308e6a2a04Slm66018 /* name_to_cons_no - convert a ldom's name to its consno */ 2318e6a2a04Slm66018 static int 2328e6a2a04Slm66018 name_to_cons_no(vntsd_group_t *groupp, char *name) 2338e6a2a04Slm66018 { 2348e6a2a04Slm66018 vntsd_cons_t *consp; 2358e6a2a04Slm66018 2368e6a2a04Slm66018 consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq, 2378e6a2a04Slm66018 (compare_func_t)cons_by_name, name); 2388e6a2a04Slm66018 2398e6a2a04Slm66018 if (consp == NULL) { 2408e6a2a04Slm66018 return (-1); 2418e6a2a04Slm66018 } 2428e6a2a04Slm66018 2438e6a2a04Slm66018 return (consp->cons_no); 2448e6a2a04Slm66018 } 2458e6a2a04Slm66018 2461ae08745Sheppo /* select a console to connect */ 2471ae08745Sheppo static int 2488e6a2a04Slm66018 select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp, 2491ae08745Sheppo vntsd_client_t *clientp, char c) 2501ae08745Sheppo { 2518e6a2a04Slm66018 int cons_no = -1; 2521ae08745Sheppo int n; 2531ae08745Sheppo int i; 2541ae08745Sheppo char buf[VNTSD_LINE_LEN]; 2551ae08745Sheppo int rv; 2561ae08745Sheppo 2571ae08745Sheppo 2581ae08745Sheppo 2591ae08745Sheppo (void) mutex_lock(&groupp->lock); 2601ae08745Sheppo if (groupp->num_cons == 0) { 2611ae08745Sheppo (void) mutex_unlock(&groupp->lock); 2621ae08745Sheppo /* no console in this group */ 2631ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 2641ae08745Sheppo } 2651ae08745Sheppo (void) mutex_unlock(&groupp->lock); 2661ae08745Sheppo 2671ae08745Sheppo 2688e6a2a04Slm66018 /* c{id} or n{name} */ 2691ae08745Sheppo 2701ae08745Sheppo n = VNTSD_LINE_LEN; 2711ae08745Sheppo 2721ae08745Sheppo if ((rv = vntsd_read_line(clientp, buf, &n)) != VNTSD_SUCCESS) { 2731ae08745Sheppo return (rv); 2741ae08745Sheppo } 2751ae08745Sheppo 2761ae08745Sheppo /* parse command */ 2771ae08745Sheppo for (i = 0; i < n; i++) { 2788e6a2a04Slm66018 switch (c) { 2791ae08745Sheppo 2808e6a2a04Slm66018 case 'c': 2818e6a2a04Slm66018 /* c{id} or c {id} */ 2828e6a2a04Slm66018 if (isspace(buf[i])) { 2831ae08745Sheppo continue; 2841ae08745Sheppo } 2851ae08745Sheppo 2868e6a2a04Slm66018 if (!isdigit(buf[i])) { 2871ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 2881ae08745Sheppo } 2898e6a2a04Slm66018 2908e6a2a04Slm66018 cons_no = atoi(buf + i); 2918e6a2a04Slm66018 break; 2928e6a2a04Slm66018 2938e6a2a04Slm66018 case 'n': 2948e6a2a04Slm66018 /* n{name) or n {name} */ 2958e6a2a04Slm66018 if (isspace(buf[i])) { 2968e6a2a04Slm66018 continue; 2978e6a2a04Slm66018 } 2988e6a2a04Slm66018 2998e6a2a04Slm66018 buf[n-1] = 0; 3008e6a2a04Slm66018 cons_no = name_to_cons_no(groupp, buf+i); 3018e6a2a04Slm66018 break; 3028e6a2a04Slm66018 3038e6a2a04Slm66018 default: 3048e6a2a04Slm66018 /* should never get here */ 3058e6a2a04Slm66018 return (VNTSD_ERR_INVALID_INPUT); 3068e6a2a04Slm66018 3078e6a2a04Slm66018 } 3088e6a2a04Slm66018 3098e6a2a04Slm66018 /* got user selection */ 3108e6a2a04Slm66018 break; 3111ae08745Sheppo } 3121ae08745Sheppo 3131ae08745Sheppo if (cons_no < 0) { 3141ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 3151ae08745Sheppo } 3161ae08745Sheppo 3171ae08745Sheppo /* get selected console */ 3181ae08745Sheppo (void) mutex_lock(&groupp->lock); 3191ae08745Sheppo 3201ae08745Sheppo *consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq, 3211ae08745Sheppo (compare_func_t)vntsd_cons_by_consno, &cons_no); 3221ae08745Sheppo 3231ae08745Sheppo if (*consp == NULL) { 3241ae08745Sheppo /* during console selection, the console has been deleted */ 3251ae08745Sheppo (void) mutex_unlock(&groupp->lock); 3261ae08745Sheppo 3271ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 3281ae08745Sheppo } 3291ae08745Sheppo if ((*consp)->status & VNTSD_CONS_DELETED) { 3301ae08745Sheppo return (VNTSD_ERR_INVALID_INPUT); 3311ae08745Sheppo } 3321ae08745Sheppo 3331ae08745Sheppo (void) mutex_unlock(&groupp->lock); 3341ae08745Sheppo 3351ae08745Sheppo return (VNTSD_SUCCESS); 3361ae08745Sheppo } 3371ae08745Sheppo 3381ae08745Sheppo /* compare if there is a match console in the gorup */ 3391ae08745Sheppo static boolean_t 3401ae08745Sheppo find_cons_in_group(vntsd_cons_t *consp_in_group, vntsd_cons_t *consp) 3411ae08745Sheppo { 3421ae08745Sheppo if (consp_in_group == consp) { 3431ae08745Sheppo return (B_TRUE); 3441ae08745Sheppo } else { 3451ae08745Sheppo return (B_FALSE); 3461ae08745Sheppo } 3471ae08745Sheppo } 3481ae08745Sheppo 3491ae08745Sheppo /* connect a client to a console */ 3501ae08745Sheppo static int 3511ae08745Sheppo connect_cons(vntsd_cons_t *consp, vntsd_client_t *clientp) 3521ae08745Sheppo { 3531ae08745Sheppo int rv, rv1; 3541ae08745Sheppo vntsd_group_t *groupp; 3551ae08745Sheppo 3561ae08745Sheppo assert(consp); 3571ae08745Sheppo groupp = consp->group; 3581ae08745Sheppo assert(groupp); 3591ae08745Sheppo assert(clientp); 3601ae08745Sheppo 3611ae08745Sheppo (void) mutex_lock(&groupp->lock); 3621ae08745Sheppo 3631ae08745Sheppo /* check if console is valid */ 3641ae08745Sheppo consp = vntsd_que_find(groupp->conspq, 3651ae08745Sheppo (compare_func_t)find_cons_in_group, consp); 3661ae08745Sheppo 3671ae08745Sheppo if (consp == NULL) { 3681ae08745Sheppo (void) mutex_unlock(&groupp->lock); 3691ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 3701ae08745Sheppo } 3711ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) { 3721ae08745Sheppo (void) mutex_unlock(&groupp->lock); 3731ae08745Sheppo return (VNTSD_STATUS_NO_CONS); 3741ae08745Sheppo } 3751ae08745Sheppo 3761ae08745Sheppo (void) mutex_lock(&consp->lock); 3771ae08745Sheppo (void) mutex_lock(&clientp->lock); 3781ae08745Sheppo 3791ae08745Sheppo 3801ae08745Sheppo clientp->cons = consp; 3811ae08745Sheppo 3821ae08745Sheppo /* enable daemon cmd */ 3831ae08745Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD; 3841ae08745Sheppo 3857636cb21Slm66018 if (consp->clientpq == NULL && consp->vcc_fd == -1) { 3867636cb21Slm66018 3877636cb21Slm66018 /* 3887636cb21Slm66018 * the first connection to a console - a writer 3897636cb21Slm66018 * and the console has not opened. 3907636cb21Slm66018 */ 3911ae08745Sheppo consp->vcc_fd = vntsd_open_vcc(consp->dev_name, consp->cons_no); 3921ae08745Sheppo if (consp->vcc_fd < 0) { 3931ae08745Sheppo (void) mutex_unlock(&clientp->lock); 3941ae08745Sheppo (void) mutex_unlock(&consp->lock); 3951ae08745Sheppo (void) mutex_unlock(&groupp->lock); 3961ae08745Sheppo assert(consp->group); 3971ae08745Sheppo return (vntsd_vcc_err(consp)); 3981ae08745Sheppo } 3991ae08745Sheppo } 4001ae08745Sheppo 4011ae08745Sheppo (void) mutex_unlock(&clientp->lock); 4021ae08745Sheppo 4031ae08745Sheppo /* 4041ae08745Sheppo * move the client from group's no console selected queue 4051ae08745Sheppo * to cons queue 4061ae08745Sheppo */ 4071ae08745Sheppo 4081ae08745Sheppo rv = vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 4091ae08745Sheppo assert(rv == VNTSD_SUCCESS); 4101ae08745Sheppo 4111ae08745Sheppo rv = vntsd_que_append(&consp->clientpq, clientp); 4121ae08745Sheppo (void) mutex_unlock(&groupp->lock); 4131ae08745Sheppo 4141ae08745Sheppo if (rv != VNTSD_SUCCESS) { 4151ae08745Sheppo if (consp->clientpq->handle == clientp) { 4161ae08745Sheppo /* writer */ 4171ae08745Sheppo (void) close(consp->vcc_fd); 4181ae08745Sheppo consp->vcc_fd = -1; 4191ae08745Sheppo } 4201ae08745Sheppo 4211ae08745Sheppo (void) mutex_unlock(&consp->lock); 4221ae08745Sheppo return (rv); 4231ae08745Sheppo } 4241ae08745Sheppo 4251ae08745Sheppo (void) mutex_unlock(&consp->lock); 4261ae08745Sheppo 4271ae08745Sheppo if (consp->clientpq->handle == clientp) { 4281ae08745Sheppo /* create a write thread */ 4291ae08745Sheppo rv = create_write_thread(consp); 4301ae08745Sheppo if (rv != VNTSD_SUCCESS) { 4311ae08745Sheppo return (rv); 4321ae08745Sheppo } 4331ae08745Sheppo } 4341ae08745Sheppo 4351ae08745Sheppo /* write connecting message */ 4361ae08745Sheppo if ((rv = write_connect_msg(clientp, consp->group->group_name, 4371ae08745Sheppo consp->domain_name)) != VNTSD_SUCCESS) { 4381ae08745Sheppo return (rv); 4391ae08745Sheppo } 4401ae08745Sheppo 4411ae08745Sheppo /* process input from client */ 4421ae08745Sheppo rv = vntsd_read(clientp); 4431ae08745Sheppo 4441ae08745Sheppo /* client disconnected from the console */ 4451ae08745Sheppo (void) mutex_lock(&groupp->lock); 4461ae08745Sheppo 4471ae08745Sheppo /* remove client from console queue */ 4481ae08745Sheppo (void) mutex_lock(&consp->lock); 4491ae08745Sheppo rv1 = vntsd_que_rm(&consp->clientpq, clientp); 4501ae08745Sheppo assert(rv1 == VNTSD_SUCCESS); 4511ae08745Sheppo 4521ae08745Sheppo /* append client to group's no console selected queue */ 4531ae08745Sheppo rv1 = vntsd_que_append(&groupp->no_cons_clientpq, clientp); 4541ae08745Sheppo (void) mutex_unlock(&groupp->lock); 4551ae08745Sheppo 4561ae08745Sheppo if (consp->clientpq == NULL) { 4571ae08745Sheppo /* clean up console since there is no client connected to it */ 4581ae08745Sheppo assert(consp->vcc_fd != -1); 4591ae08745Sheppo 4601ae08745Sheppo /* force write thread to exit */ 4611ae08745Sheppo assert(consp->wr_tid != (thread_t)-1); 4621ae08745Sheppo (void) thr_kill(consp->wr_tid, SIGUSR1); 4631ae08745Sheppo (void) mutex_unlock(&consp->lock); 4641ae08745Sheppo (void) thr_join(consp->wr_tid, NULL, NULL); 4651ae08745Sheppo (void) mutex_lock(&consp->lock); 4661ae08745Sheppo } 4671ae08745Sheppo 4681ae08745Sheppo if (consp->status & VNTSD_CONS_SIG_WAIT) { 4691ae08745Sheppo /* console is waiting for client to disconnect */ 4701ae08745Sheppo (void) cond_signal(&consp->cvp); 4711ae08745Sheppo } 4721ae08745Sheppo 4731ae08745Sheppo (void) mutex_unlock(&consp->lock); 4741ae08745Sheppo 4751ae08745Sheppo return (rv1 == VNTSD_SUCCESS ? rv : rv1); 4761ae08745Sheppo 4771ae08745Sheppo } 4781ae08745Sheppo 4791ae08745Sheppo /* read command line input */ 4801ae08745Sheppo static int 4811ae08745Sheppo read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd) 4821ae08745Sheppo { 4831ae08745Sheppo int rv; 4841ae08745Sheppo 4851ae08745Sheppo /* disable daemon special command */ 4861ae08745Sheppo (void) mutex_lock(&clientp->lock); 4871ae08745Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD; 4881ae08745Sheppo (void) mutex_unlock(&clientp->lock); 4891ae08745Sheppo 4901ae08745Sheppo if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) 4911ae08745Sheppo != VNTSD_SUCCESS) { 4921ae08745Sheppo return (rv); 4931ae08745Sheppo } 4941ae08745Sheppo 4951ae08745Sheppo if ((rv = vntsd_write_client(clientp, prompt, strlen(prompt))) 4961ae08745Sheppo != VNTSD_SUCCESS) { 4971ae08745Sheppo return (rv); 4981ae08745Sheppo } 4991ae08745Sheppo 5001ae08745Sheppo if ((rv = vntsd_read_data(clientp, cmd)) != VNTSD_SUCCESS) { 5011ae08745Sheppo return (rv); 5021ae08745Sheppo } 5031ae08745Sheppo if (*cmd == BS) { 5041ae08745Sheppo return (VNTSD_SUCCESS); 5051ae08745Sheppo } 5061ae08745Sheppo 5071ae08745Sheppo rv = vntsd_write_client(clientp, cmd, 1); 5081ae08745Sheppo 5091ae08745Sheppo *cmd = tolower(*cmd); 5101ae08745Sheppo 5111ae08745Sheppo return (rv); 5121ae08745Sheppo } 5131ae08745Sheppo 5141ae08745Sheppo /* reset client for selecting a console in the group */ 5151ae08745Sheppo static void 5161ae08745Sheppo client_init(vntsd_client_t *clientp) 5171ae08745Sheppo { 5181ae08745Sheppo (void) mutex_lock(&clientp->lock); 5191ae08745Sheppo clientp->cons = NULL; 5201ae08745Sheppo clientp->status = 0; 5211ae08745Sheppo (void) mutex_unlock(&clientp->lock); 5221ae08745Sheppo } 5237636cb21Slm66018 /* is there any connection to a given console? */ 5247636cb21Slm66018 static boolean_t 5257636cb21Slm66018 is_client_que_empty(vntsd_cons_t *consp) 5267636cb21Slm66018 { 5277636cb21Slm66018 boolean_t has_client = B_FALSE; 5287636cb21Slm66018 5297636cb21Slm66018 (void) mutex_lock(&consp->lock); 5307636cb21Slm66018 5317636cb21Slm66018 if (consp->clientpq != NULL) 5327636cb21Slm66018 has_client = B_TRUE; 5337636cb21Slm66018 5347636cb21Slm66018 (void) mutex_unlock(&consp->lock); 5357636cb21Slm66018 5367636cb21Slm66018 return (has_client); 5377636cb21Slm66018 } 5387636cb21Slm66018 5397636cb21Slm66018 /* 5407636cb21Slm66018 * close one opened console. 5417636cb21Slm66018 * This function is passed to vntsd_que_walk to close one console. 5427636cb21Slm66018 * The function returns B_FALSE so that vntsd_que_walk will 5437636cb21Slm66018 * continue to apply the function to all consoles in the group. 5447636cb21Slm66018 */ 5457636cb21Slm66018 static boolean_t 5467636cb21Slm66018 close_one_vcc_fd(vntsd_cons_t *consp) 5477636cb21Slm66018 { 5487636cb21Slm66018 (void) mutex_lock(&consp->lock); 5497636cb21Slm66018 5507636cb21Slm66018 if (consp->vcc_fd != -1) { 5517636cb21Slm66018 (void) close(consp->vcc_fd); 5527636cb21Slm66018 consp->vcc_fd = -1; 5537636cb21Slm66018 } 5547636cb21Slm66018 5557636cb21Slm66018 (void) mutex_unlock(&consp->lock); 5567636cb21Slm66018 5577636cb21Slm66018 return (B_FALSE); 5587636cb21Slm66018 } 5597636cb21Slm66018 5601ae08745Sheppo 5611ae08745Sheppo /* clean up client and exit the thread */ 5621ae08745Sheppo static void 5631ae08745Sheppo client_fini(vntsd_group_t *groupp, vntsd_client_t *clientp) 5641ae08745Sheppo { 5651ae08745Sheppo 5661ae08745Sheppo assert(groupp); 5671ae08745Sheppo assert(clientp); 5681ae08745Sheppo 5691ae08745Sheppo /* disconnct client from tcp port */ 5701ae08745Sheppo assert(clientp->sockfd != -1); 5711ae08745Sheppo (void) close(clientp->sockfd); 5721ae08745Sheppo 5731ae08745Sheppo (void) mutex_lock(&groupp->lock); 5747636cb21Slm66018 5757636cb21Slm66018 /* 5767636cb21Slm66018 * close all consoles in the group if the client is the 5777636cb21Slm66018 * last one connected to the group 5787636cb21Slm66018 */ 5797636cb21Slm66018 if (vntsd_que_walk(groupp->conspq, (el_func_t)is_client_que_empty) == 5807636cb21Slm66018 VNTSD_SUCCESS) { 5817636cb21Slm66018 (void) vntsd_que_walk(groupp->conspq, 5827636cb21Slm66018 (el_func_t)close_one_vcc_fd); 5837636cb21Slm66018 } 5847636cb21Slm66018 5857636cb21Slm66018 5861ae08745Sheppo (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp); 5871ae08745Sheppo 5881ae08745Sheppo if ((groupp->no_cons_clientpq == NULL) && 5891ae08745Sheppo (groupp->status & VNTSD_GROUP_SIG_WAIT)) { 5904d39be2bSsg70180 /* 5914d39be2bSsg70180 * group is waiting to be deleted. - signal the group's 5924d39be2bSsg70180 * listen thread - the VNTSD_GROUP_SIG_WAIT state will 5934d39be2bSsg70180 * be cleared when the listen thread exits. 5944d39be2bSsg70180 */ 5951ae08745Sheppo (void) cond_signal(&groupp->cvp); 5961ae08745Sheppo } 5971ae08745Sheppo (void) mutex_unlock(&groupp->lock); 5981ae08745Sheppo 5991ae08745Sheppo (void) mutex_destroy(&clientp->lock); 6001ae08745Sheppo free(clientp); 6011ae08745Sheppo 6021ae08745Sheppo thr_exit(0); 6031ae08745Sheppo } 6041ae08745Sheppo 6051ae08745Sheppo /* check client's status. exit if client quits or fatal errors */ 6061ae08745Sheppo static void 6071ae08745Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status) 6081ae08745Sheppo { 6091ae08745Sheppo char err_msg[VNTSD_LINE_LEN]; 6101ae08745Sheppo 6111ae08745Sheppo D1(stderr, "t@%d console_chk_status() status=%d " 6121ae08745Sheppo "client status=%x num consoles=%d \n", 6131ae08745Sheppo thr_self(), status, clientp->status, groupp->num_cons); 6141ae08745Sheppo 6151ae08745Sheppo (void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d" 6161ae08745Sheppo " num_cos=%d", clientp->sockfd, groupp->num_cons); 6171ae08745Sheppo 6184d39be2bSsg70180 /* 6194d39be2bSsg70180 * obtain group lock to protect groupp->num_cons. 6204d39be2bSsg70180 * When groupp->num_cons == 0, close client and exit the tread. 6214d39be2bSsg70180 */ 6224d39be2bSsg70180 (void) mutex_lock(&groupp->lock); 6234d39be2bSsg70180 6241ae08745Sheppo if (groupp->num_cons == 0) { 6251ae08745Sheppo /* no more console in the group */ 6264d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6271ae08745Sheppo client_fini(groupp, clientp); 6284d39be2bSsg70180 return; 6291ae08745Sheppo } 6301ae08745Sheppo 6311ae08745Sheppo if (status == VNTSD_STATUS_INTR) { 6321ae08745Sheppo /* reason for signal? */ 6331ae08745Sheppo status = vntsd_cons_chk_intr(clientp); 6341ae08745Sheppo } 6351ae08745Sheppo 6361ae08745Sheppo switch (status) { 6371ae08745Sheppo 6381ae08745Sheppo case VNTSD_STATUS_CLIENT_QUIT: 6394d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6401ae08745Sheppo client_fini(groupp, clientp); 6411ae08745Sheppo return; 6421ae08745Sheppo 6431ae08745Sheppo case VNTSD_STATUS_RESELECT_CONS: 6444d39be2bSsg70180 6454d39be2bSsg70180 if (clientp->cons == NULL) { 6464d39be2bSsg70180 /* 6474d39be2bSsg70180 * domain was deleted before client connects to it 6484d39be2bSsg70180 * connect to other console in the same group 6494d39be2bSsg70180 */ 6504d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6514d39be2bSsg70180 client_init(clientp); 6524d39be2bSsg70180 return; 6534d39be2bSsg70180 } 6544d39be2bSsg70180 6551ae08745Sheppo if ((groupp->num_cons == 1) && 6564d39be2bSsg70180 ((clientp->status & VNTSD_CLIENT_CONS_DELETED) || 6574d39be2bSsg70180 (groupp->conspq->handle == clientp->cons))) { 6581ae08745Sheppo /* no other selection available */ 6594d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6601ae08745Sheppo client_fini(groupp, clientp); 6611ae08745Sheppo } else { 6624d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6631ae08745Sheppo client_init(clientp); 6641ae08745Sheppo } 6654d39be2bSsg70180 6661ae08745Sheppo return; 6671ae08745Sheppo 6681ae08745Sheppo case VNTSD_STATUS_VCC_IO_ERR: 6691ae08745Sheppo if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) { 6701ae08745Sheppo /* check if console was deleted */ 6714d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6721ae08745Sheppo status = vntsd_vcc_err(clientp->cons); 6734d39be2bSsg70180 (void) mutex_lock(&groupp->lock); 6741ae08745Sheppo } 6751ae08745Sheppo 6761ae08745Sheppo if (status != VNTSD_STATUS_CONTINUE) { 6771ae08745Sheppo /* console was deleted */ 6784d39be2bSsg70180 if (groupp->num_cons <= 1) { 6794d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6801ae08745Sheppo client_fini(groupp, clientp); 6814d39be2bSsg70180 return; 6821ae08745Sheppo } 6831ae08745Sheppo } 6841ae08745Sheppo 6854d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6861ae08745Sheppo /* console is ok */ 6871ae08745Sheppo client_init(clientp); 6881ae08745Sheppo return; 6891ae08745Sheppo 6901ae08745Sheppo case VNTSD_STATUS_MOV_CONS_FORWARD: 6911ae08745Sheppo case VNTSD_STATUS_MOV_CONS_BACKWARD: 6921ae08745Sheppo if (groupp->num_cons == 1) { 6931ae08745Sheppo /* same console */ 6944d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 6951ae08745Sheppo return; 6961ae08745Sheppo } 6971ae08745Sheppo 6981ae08745Sheppo /* get selected console */ 6994d39be2bSsg70180 clientp->cons = vntsd_que_pos(groupp->conspq, 7001ae08745Sheppo clientp->cons, 7011ae08745Sheppo (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1)); 7024d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 7031ae08745Sheppo return; 7041ae08745Sheppo 7051ae08745Sheppo case VNTSD_SUCCESS: 7061ae08745Sheppo case VNTSD_STATUS_CONTINUE: 7074d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 7081ae08745Sheppo client_init(clientp); 7091ae08745Sheppo return; 7101ae08745Sheppo 711*3c96341aSnarayan 712*3c96341aSnarayan case VNTSD_STATUS_NO_CONS: 713*3c96341aSnarayan /* 714*3c96341aSnarayan * there are two cases when the status is VNTSD_SATATUS_NO_CONS. 715*3c96341aSnarayan * case 1. the console was removed but there is at least one 716*3c96341aSnarayan * another console in the group that client can connect to. 717*3c96341aSnarayan * case 2. there is no console in the group. Client needs to 718*3c96341aSnarayan * be disconnected from vntsd. 719*3c96341aSnarayan */ 720*3c96341aSnarayan if (groupp->num_cons == 0) { 721*3c96341aSnarayan (void) mutex_unlock(&groupp->lock); 722*3c96341aSnarayan client_fini(groupp, clientp); 723*3c96341aSnarayan } else { 724*3c96341aSnarayan (void) mutex_unlock(&groupp->lock); 725*3c96341aSnarayan client_init(clientp); 726*3c96341aSnarayan } 727*3c96341aSnarayan return; 728*3c96341aSnarayan 729*3c96341aSnarayan 7301ae08745Sheppo case VNTSD_ERR_INVALID_INPUT: 7314d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 7321ae08745Sheppo return; 7331ae08745Sheppo 7341ae08745Sheppo default: 7351ae08745Sheppo /* fatal error */ 7364d39be2bSsg70180 (void) mutex_unlock(&groupp->lock); 7371ae08745Sheppo vntsd_log(status, err_msg); 7381ae08745Sheppo client_fini(groupp, clientp); 7391ae08745Sheppo return; 7401ae08745Sheppo } 7411ae08745Sheppo } 7421ae08745Sheppo 7431ae08745Sheppo /* console thread */ 7441ae08745Sheppo void * 7451ae08745Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp) 7461ae08745Sheppo { 7471ae08745Sheppo vntsd_group_t *groupp; 7481ae08745Sheppo vntsd_cons_t *consp; 7491ae08745Sheppo vntsd_client_t *clientp; 7501ae08745Sheppo 7511ae08745Sheppo char buf[MAXHOSTNAMELEN]; 7521ae08745Sheppo char prompt[72]; 7531ae08745Sheppo char cmd; 7541ae08745Sheppo int rv = VNTSD_SUCCESS; 7551ae08745Sheppo int num_cons; 7561ae08745Sheppo 7571ae08745Sheppo 7581ae08745Sheppo groupp = (vntsd_group_t *)argp->handle; 7591ae08745Sheppo clientp = (vntsd_client_t *)argp->arg; 7601ae08745Sheppo 7611ae08745Sheppo assert(groupp); 7621ae08745Sheppo assert(clientp); 7631ae08745Sheppo 764*3c96341aSnarayan /* free argp, which was allocated in listen thread */ 765*3c96341aSnarayan free(argp); 766*3c96341aSnarayan 7671ae08745Sheppo /* check if group is removed */ 7681ae08745Sheppo 7691ae08745Sheppo D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(), 7701ae08745Sheppo groupp->tcp_port, clientp->sockfd); 7711ae08745Sheppo 7721ae08745Sheppo bzero(buf, MAXHOSTNAMELEN); 7731ae08745Sheppo 7741ae08745Sheppo /* host name */ 7751ae08745Sheppo if (gethostname(buf, MAXHOSTNAMELEN)) { 7761ae08745Sheppo vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()"); 7771ae08745Sheppo (void) snprintf(buf, sizeof (buf), "unkown host"); 7781ae08745Sheppo } 7791ae08745Sheppo 7801ae08745Sheppo if (snprintf(prompt, sizeof (prompt), 7818e6a2a04Slm66018 "%s-vnts-%s: h, l, c{id}, n{name}, q:", 7821ae08745Sheppo buf, groupp->group_name) >= sizeof (prompt)) { 7831ae08745Sheppo /* long prompt doesn't fit, use short one */ 7841ae08745Sheppo (void) snprintf(prompt, sizeof (prompt), 7858e6a2a04Slm66018 "vnts: h, l, c{id}, n{name}, q:"); 7861ae08745Sheppo } 7871ae08745Sheppo 7881ae08745Sheppo 7891ae08745Sheppo for (;;) { 7901ae08745Sheppo cmd = ' '; 7911ae08745Sheppo D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(), 7921ae08745Sheppo groupp->tcp_port, clientp->sockfd); 7931ae08745Sheppo 7941ae08745Sheppo num_cons = vntsd_chk_group_total_cons(groupp); 7951ae08745Sheppo 7961ae08745Sheppo if ((num_cons > 1) && (clientp->cons == NULL)) { 7971ae08745Sheppo /* console to connect to */ 7981ae08745Sheppo rv = read_cmd(clientp, prompt, &cmd); 7991ae08745Sheppo /* check error and may exit */ 8001ae08745Sheppo console_chk_status(groupp, clientp, rv); 8014d39be2bSsg70180 8024d39be2bSsg70180 /* any console is removed from group? */ 8034d39be2bSsg70180 num_cons = vntsd_chk_group_total_cons(groupp); 8044d39be2bSsg70180 if (num_cons <= 1) { 8054d39be2bSsg70180 cmd = ' '; 8064d39be2bSsg70180 } 8071ae08745Sheppo } 8081ae08745Sheppo 8091ae08745Sheppo switch (cmd) { 8101ae08745Sheppo 8111ae08745Sheppo case 'l': 8121ae08745Sheppo 8131ae08745Sheppo /* list domain names */ 8141ae08745Sheppo rv = list_all_domains(groupp, clientp); 8151ae08745Sheppo break; 8161ae08745Sheppo 8171ae08745Sheppo 8181ae08745Sheppo case 'q': 8191ae08745Sheppo 8201ae08745Sheppo rv = VNTSD_STATUS_CLIENT_QUIT; 8211ae08745Sheppo break; 8221ae08745Sheppo 8238e6a2a04Slm66018 case ' ': 8248e6a2a04Slm66018 825*3c96341aSnarayan if (num_cons == 0) { 8264d39be2bSsg70180 /* no console in the group */ 827*3c96341aSnarayan rv = VNTSD_STATUS_NO_CONS; 8284d39be2bSsg70180 break; 829*3c96341aSnarayan } 8304d39be2bSsg70180 8318e6a2a04Slm66018 if (clientp->cons == NULL) { 8328e6a2a04Slm66018 if (num_cons == 1) { 8338e6a2a04Slm66018 /* by pass selecting console */ 8348e6a2a04Slm66018 consp = (vntsd_cons_t *) 8358e6a2a04Slm66018 (groupp->conspq->handle); 8368e6a2a04Slm66018 } else { 8378e6a2a04Slm66018 continue; 8388e6a2a04Slm66018 } 8398e6a2a04Slm66018 8408e6a2a04Slm66018 } else { 8418e6a2a04Slm66018 consp = clientp->cons; 8428e6a2a04Slm66018 } 8438e6a2a04Slm66018 8448e6a2a04Slm66018 /* connect to console */ 8458e6a2a04Slm66018 rv = connect_cons(consp, clientp); 8468e6a2a04Slm66018 8471ae08745Sheppo break; 8481ae08745Sheppo 8498e6a2a04Slm66018 case 'c': 8508e6a2a04Slm66018 case 'n': 8511ae08745Sheppo /* select console */ 8521ae08745Sheppo if (clientp->cons == NULL) { 8538e6a2a04Slm66018 rv = select_cons(groupp, &consp, clientp, cmd); 8541ae08745Sheppo if (rv == VNTSD_ERR_INVALID_INPUT) { 8551ae08745Sheppo rv = display_help(clientp); 8561ae08745Sheppo break; 8571ae08745Sheppo } 858*3c96341aSnarayan 859*3c96341aSnarayan /* 860*3c96341aSnarayan * all consoles in the group 861*3c96341aSnarayan * may be gone before this client 862*3c96341aSnarayan * could select one. 863*3c96341aSnarayan */ 864*3c96341aSnarayan if (rv != VNTSD_SUCCESS) 865*3c96341aSnarayan break; 866*3c96341aSnarayan 8671ae08745Sheppo } else { 8681ae08745Sheppo consp = clientp->cons; 8691ae08745Sheppo } 8701ae08745Sheppo assert(consp); 8711ae08745Sheppo 8721ae08745Sheppo /* connect to console */ 8731ae08745Sheppo rv = connect_cons(consp, clientp); 8741ae08745Sheppo D1(stderr, "t@%d console_thread()" 8751ae08745Sheppo "connect_cons returns %d\n", 8761ae08745Sheppo thr_self(), rv); 8771ae08745Sheppo break; 8781ae08745Sheppo 8798e6a2a04Slm66018 case 'h': 8808e6a2a04Slm66018 default: 8818e6a2a04Slm66018 rv = display_help(clientp); 8828e6a2a04Slm66018 break; 8838e6a2a04Slm66018 8841ae08745Sheppo } 8858e6a2a04Slm66018 8861ae08745Sheppo /* check error and may exit */ 8871ae08745Sheppo console_chk_status(groupp, clientp, rv); 8881ae08745Sheppo } 8891ae08745Sheppo 8901ae08745Sheppo /*NOTREACHED*/ 8911ae08745Sheppo return (NULL); 8921ae08745Sheppo } 893