xref: /onnv-gate/usr/src/cmd/vntsd/console.c (revision 2748:85615553b3bb)
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 
385*2748Slm66018 	if (consp->clientpq == NULL && consp->vcc_fd == -1) {
386*2748Slm66018 
387*2748Slm66018 		/*
388*2748Slm66018 		 *  the first connection to a console - a writer
389*2748Slm66018 		 *  and the console has not opened.
390*2748Slm66018 		 */
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 }
523*2748Slm66018 /* is there any connection to a given console? */
524*2748Slm66018 static boolean_t
525*2748Slm66018 is_client_que_empty(vntsd_cons_t *consp)
526*2748Slm66018 {
527*2748Slm66018 	boolean_t  has_client = B_FALSE;
528*2748Slm66018 
529*2748Slm66018 	(void) mutex_lock(&consp->lock);
530*2748Slm66018 
531*2748Slm66018 	if (consp->clientpq != NULL)
532*2748Slm66018 		has_client = B_TRUE;
533*2748Slm66018 
534*2748Slm66018 	(void) mutex_unlock(&consp->lock);
535*2748Slm66018 
536*2748Slm66018 	return (has_client);
537*2748Slm66018 }
538*2748Slm66018 
539*2748Slm66018 /*
540*2748Slm66018  * close one opened console.
541*2748Slm66018  * This function is passed to vntsd_que_walk to close one console.
542*2748Slm66018  * The function returns B_FALSE so that vntsd_que_walk will
543*2748Slm66018  * continue to apply the function to all consoles in the group.
544*2748Slm66018  */
545*2748Slm66018 static boolean_t
546*2748Slm66018 close_one_vcc_fd(vntsd_cons_t *consp)
547*2748Slm66018 {
548*2748Slm66018 	(void) mutex_lock(&consp->lock);
549*2748Slm66018 
550*2748Slm66018 	if (consp->vcc_fd != -1) {
551*2748Slm66018 		(void) close(consp->vcc_fd);
552*2748Slm66018 		consp->vcc_fd = -1;
553*2748Slm66018 	}
554*2748Slm66018 
555*2748Slm66018 	(void) mutex_unlock(&consp->lock);
556*2748Slm66018 
557*2748Slm66018 	return (B_FALSE);
558*2748Slm66018 }
559*2748Slm66018 
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);
574*2748Slm66018 
575*2748Slm66018 	/*
576*2748Slm66018 	 * close all consoles in the group if the client is the
577*2748Slm66018 	 * last one connected to the group
578*2748Slm66018 	 */
579*2748Slm66018 	if (vntsd_que_walk(groupp->conspq, (el_func_t)is_client_que_empty) ==
580*2748Slm66018 	    VNTSD_SUCCESS) {
581*2748Slm66018 		(void) vntsd_que_walk(groupp->conspq,
582*2748Slm66018 		    (el_func_t)close_one_vcc_fd);
583*2748Slm66018 	}
584*2748Slm66018 
585*2748Slm66018 
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)) {
5901991Sheppo 		/* group is waiting to be deleted */
5911991Sheppo 		groupp->status &= ~VNTSD_GROUP_SIG_WAIT;
5921991Sheppo 		(void) cond_signal(&groupp->cvp);
5931991Sheppo 	}
5941991Sheppo 	(void) mutex_unlock(&groupp->lock);
5951991Sheppo 
5961991Sheppo 	(void) mutex_destroy(&clientp->lock);
5971991Sheppo 	free(clientp);
5981991Sheppo 
5991991Sheppo 	thr_exit(0);
6001991Sheppo }
6011991Sheppo 
6021991Sheppo /*  check client's status. exit if client quits or fatal errors */
6031991Sheppo static void
6041991Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status)
6051991Sheppo {
6061991Sheppo 	char    err_msg[VNTSD_LINE_LEN];
6071991Sheppo 
6081991Sheppo 	D1(stderr, "t@%d console_chk_status() status=%d "
6091991Sheppo 	    "client status=%x num consoles=%d \n",
6101991Sheppo 	    thr_self(), status, clientp->status, groupp->num_cons);
6111991Sheppo 
6121991Sheppo 	(void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d"
6131991Sheppo 	    " num_cos=%d", clientp->sockfd, groupp->num_cons);
6141991Sheppo 
6151991Sheppo 	if (groupp->num_cons == 0) {
6161991Sheppo 		/* no more console in the group */
6171991Sheppo 		client_fini(groupp, clientp);
6181991Sheppo 	}
6191991Sheppo 
6201991Sheppo 	if (status == VNTSD_STATUS_INTR) {
6211991Sheppo 		/* reason for signal? */
6221991Sheppo 		status = vntsd_cons_chk_intr(clientp);
6231991Sheppo 	}
6241991Sheppo 
6251991Sheppo 	switch (status) {
6261991Sheppo 
6271991Sheppo 	case VNTSD_STATUS_CLIENT_QUIT:
6281991Sheppo 		client_fini(groupp, clientp);
6291991Sheppo 		return;
6301991Sheppo 
6311991Sheppo 	case VNTSD_STATUS_RESELECT_CONS:
6321991Sheppo 		assert(clientp->cons);
6331991Sheppo 		if ((groupp->num_cons == 1) &&
6341991Sheppo 		    (groupp->conspq->handle == clientp->cons)) {
6351991Sheppo 			/* no other selection available */
6361991Sheppo 			client_fini(groupp, clientp);
6371991Sheppo 		} else {
6381991Sheppo 			client_init(clientp);
6391991Sheppo 		}
6401991Sheppo 		return;
6411991Sheppo 
6421991Sheppo 	case VNTSD_STATUS_VCC_IO_ERR:
6431991Sheppo 		if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) {
6441991Sheppo 			/* check if console was deleted  */
6451991Sheppo 			status = vntsd_vcc_err(clientp->cons);
6461991Sheppo 		}
6471991Sheppo 
6481991Sheppo 		if (status != VNTSD_STATUS_CONTINUE) {
6491991Sheppo 			/* console was deleted */
6501991Sheppo 			if (groupp->num_cons == 1) {
6511991Sheppo 				client_fini(groupp, clientp);
6521991Sheppo 			}
6531991Sheppo 		}
6541991Sheppo 
6551991Sheppo 		/* console is ok */
6561991Sheppo 		client_init(clientp);
6571991Sheppo 		return;
6581991Sheppo 
6591991Sheppo 	case VNTSD_STATUS_MOV_CONS_FORWARD:
6601991Sheppo 	case VNTSD_STATUS_MOV_CONS_BACKWARD:
6611991Sheppo 		if (groupp->num_cons == 1) {
6621991Sheppo 			/* same console */
6631991Sheppo 			return;
6641991Sheppo 		}
6651991Sheppo 
6661991Sheppo 		/* get selected console */
6671991Sheppo 		(void) mutex_lock(&(clientp->cons->group->lock));
6681991Sheppo 		clientp->cons = vntsd_que_pos(clientp->cons->group->conspq,
6691991Sheppo 		    clientp->cons,
6701991Sheppo 		    (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1));
6711991Sheppo 		(void) mutex_unlock(&(clientp->cons->group->lock));
6721991Sheppo 		return;
6731991Sheppo 
6741991Sheppo 	case VNTSD_SUCCESS:
6751991Sheppo 	case VNTSD_STATUS_CONTINUE:
6761991Sheppo 	case VNTSD_STATUS_NO_CONS:
6771991Sheppo 		client_init(clientp);
6781991Sheppo 		return;
6791991Sheppo 
6801991Sheppo 	case VNTSD_ERR_INVALID_INPUT:
6811991Sheppo 		return;
6821991Sheppo 
6831991Sheppo 	default:
6841991Sheppo 		/* fatal error */
6851991Sheppo 		vntsd_log(status, err_msg);
6861991Sheppo 		client_fini(groupp, clientp);
6871991Sheppo 		return;
6881991Sheppo 	}
6891991Sheppo }
6901991Sheppo 
6911991Sheppo /* console thread */
6921991Sheppo void *
6931991Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp)
6941991Sheppo {
6951991Sheppo 	vntsd_group_t	    *groupp;
6961991Sheppo 	vntsd_cons_t	    *consp;
6971991Sheppo 	vntsd_client_t	    *clientp;
6981991Sheppo 
6991991Sheppo 	char		    buf[MAXHOSTNAMELEN];
7001991Sheppo 	char		    prompt[72];
7011991Sheppo 	char		    cmd;
7021991Sheppo 	int		    rv = VNTSD_SUCCESS;
7031991Sheppo 	int		    num_cons;
7041991Sheppo 
7051991Sheppo 
7061991Sheppo 	groupp = (vntsd_group_t *)argp->handle;
7071991Sheppo 	clientp = (vntsd_client_t *)argp->arg;
7081991Sheppo 
7091991Sheppo 	assert(groupp);
7101991Sheppo 	assert(clientp);
7111991Sheppo 
7121991Sheppo 	/* check if group is removed */
7131991Sheppo 
7141991Sheppo 	D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(),
7151991Sheppo 	    groupp->tcp_port, clientp->sockfd);
7161991Sheppo 
7171991Sheppo 	bzero(buf, MAXHOSTNAMELEN);
7181991Sheppo 
7191991Sheppo 	/* host name */
7201991Sheppo 	if (gethostname(buf, MAXHOSTNAMELEN)) {
7211991Sheppo 		vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()");
7221991Sheppo 		(void) snprintf(buf, sizeof (buf), "unkown host");
7231991Sheppo 	}
7241991Sheppo 
7251991Sheppo 	if (snprintf(prompt, sizeof (prompt),
7262109Slm66018 		    "%s-vnts-%s: h, l, c{id}, n{name}, q:",
7271991Sheppo 	    buf, groupp->group_name) >= sizeof (prompt)) {
7281991Sheppo 		/* long prompt doesn't fit, use short one */
7291991Sheppo 		(void) snprintf(prompt, sizeof (prompt),
7302109Slm66018 				"vnts: h, l, c{id}, n{name}, q:");
7311991Sheppo 	}
7321991Sheppo 
7331991Sheppo 
7341991Sheppo 	for (;;) {
7351991Sheppo 		cmd = ' ';
7361991Sheppo 		D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(),
7371991Sheppo 		    groupp->tcp_port, clientp->sockfd);
7381991Sheppo 
7391991Sheppo 		num_cons = vntsd_chk_group_total_cons(groupp);
7401991Sheppo 
7411991Sheppo 		if ((num_cons > 1) && (clientp->cons == NULL)) {
7421991Sheppo 			/*  console to connect to */
7431991Sheppo 			rv = read_cmd(clientp, prompt, &cmd);
7441991Sheppo 			/* check error and may exit */
7451991Sheppo 			console_chk_status(groupp, clientp, rv);
7461991Sheppo 		}
7471991Sheppo 
7481991Sheppo 		switch (cmd) {
7491991Sheppo 
7501991Sheppo 		case 'l':
7511991Sheppo 
7521991Sheppo 			/* list domain names */
7531991Sheppo 			rv = list_all_domains(groupp, clientp);
7541991Sheppo 			break;
7551991Sheppo 
7561991Sheppo 
7571991Sheppo 		case 'q':
7581991Sheppo 
7591991Sheppo 			rv = VNTSD_STATUS_CLIENT_QUIT;
7601991Sheppo 			break;
7611991Sheppo 
7622109Slm66018 		case ' ':
7632109Slm66018 
7642109Slm66018 			if (clientp->cons == NULL) {
7652109Slm66018 				if (num_cons == 1) {
7662109Slm66018 					/* by pass selecting console */
7672109Slm66018 					consp = (vntsd_cons_t *)
7682109Slm66018 					    (groupp->conspq->handle);
7692109Slm66018 				} else {
7702109Slm66018 					continue;
7712109Slm66018 				}
7722109Slm66018 
7732109Slm66018 			} else {
7742109Slm66018 				consp = clientp->cons;
7752109Slm66018 			}
7762109Slm66018 
7772109Slm66018 			/* connect to console */
7782109Slm66018 			rv = connect_cons(consp, clientp);
7792109Slm66018 
7801991Sheppo 			break;
7811991Sheppo 
7822109Slm66018 		case 'c':
7832109Slm66018 		case 'n':
7841991Sheppo 			/* select console */
7851991Sheppo 			if (clientp->cons == NULL) {
7862109Slm66018 				rv = select_cons(groupp, &consp, clientp, cmd);
7871991Sheppo 				if (rv == VNTSD_ERR_INVALID_INPUT) {
7881991Sheppo 					rv = display_help(clientp);
7891991Sheppo 					break;
7901991Sheppo 				}
7911991Sheppo 			} else {
7921991Sheppo 				consp = clientp->cons;
7931991Sheppo 			}
7941991Sheppo 			assert(consp);
7951991Sheppo 
7961991Sheppo 			/* connect to console */
7971991Sheppo 			rv = connect_cons(consp, clientp);
7981991Sheppo 			D1(stderr, "t@%d console_thread()"
7991991Sheppo 			    "connect_cons returns %d\n",
8001991Sheppo 			    thr_self(), rv);
8011991Sheppo 			break;
8021991Sheppo 
8032109Slm66018 		case 'h':
8042109Slm66018 		default:
8052109Slm66018 			rv = display_help(clientp);
8062109Slm66018 			break;
8072109Slm66018 
8081991Sheppo 		}
8092109Slm66018 
8101991Sheppo 		/* check error and may  exit */
8111991Sheppo 		console_chk_status(groupp, clientp, rv);
8121991Sheppo 	}
8131991Sheppo 
8141991Sheppo 	/*NOTREACHED*/
8151991Sheppo 	return (NULL);
8161991Sheppo }
817