xref: /titanic_51/usr/src/cmd/vntsd/console.c (revision 3c96341aef2b4da56c902941f089284b52bd573f)
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