xref: /illumos-gate/usr/src/cmd/vntsd/console.c (revision 476d5ff7)
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 /*
223c96341aSnarayan  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
231ae08745Sheppo  * Use is subject to license terms.
241ae08745Sheppo  */
251ae08745Sheppo 
261ae08745Sheppo /*
271ae08745Sheppo  * Listen thread creates a console thread whenever there is a tcp client
281ae08745Sheppo  * made a conection to its port. In the console thread, if there are
291ae08745Sheppo  * multiple consoles in the group, client will be asked for a console selection.
301ae08745Sheppo  * a write thread for a console is created when first client connects to a
311ae08745Sheppo  * selected console and console thread becomes read thread for the client.
321ae08745Sheppo  */
331ae08745Sheppo 
341ae08745Sheppo #include <stdio.h>
351ae08745Sheppo #include <stdlib.h>
361ae08745Sheppo #include <string.h>
371ae08745Sheppo #include <unistd.h>
381ae08745Sheppo #include <sys/types.h>
391ae08745Sheppo #include <sys/socket.h>
401ae08745Sheppo #include <netinet/in.h>
411ae08745Sheppo #include <thread.h>
421ae08745Sheppo #include <synch.h>
431ae08745Sheppo #include <signal.h>
441ae08745Sheppo #include <assert.h>
451ae08745Sheppo #include <ctype.h>
461ae08745Sheppo #include <syslog.h>
471ae08745Sheppo #include <libintl.h>
481ae08745Sheppo #include <netdb.h>
491ae08745Sheppo #include "vntsd.h"
501ae08745Sheppo #include "chars.h"
511ae08745Sheppo 
521ae08745Sheppo /*  display domain names in the group */
531ae08745Sheppo static boolean_t
display_domain_name(vntsd_cons_t * consp,int * fd)541ae08745Sheppo display_domain_name(vntsd_cons_t *consp,  int  *fd)
551ae08745Sheppo {
561ae08745Sheppo 	char	buf[VNTSD_LINE_LEN];
571ae08745Sheppo 	char	*status;
581ae08745Sheppo 
591ae08745Sheppo 
601ae08745Sheppo 	if (consp->clientpq != NULL) {
611ae08745Sheppo 		status = gettext("connected");
621ae08745Sheppo 	} else if (consp->status & VNTSD_CONS_DELETED) {
631ae08745Sheppo 		status = gettext("removing...");
641ae08745Sheppo 	} else {
651ae08745Sheppo 		status = gettext("online");
661ae08745Sheppo 	}
671ae08745Sheppo 
681ae08745Sheppo 	(void) snprintf(buf, sizeof (buf), "%-20d%-30s%-25s%s",
691ae08745Sheppo 	    consp->cons_no, consp->domain_name, status, vntsd_eol);
701ae08745Sheppo 
711ae08745Sheppo 	return (vntsd_write_fd(*fd, buf, strlen(buf)) != VNTSD_SUCCESS);
721ae08745Sheppo }
731ae08745Sheppo 
741ae08745Sheppo /* output connected message to tcp client */
751ae08745Sheppo static int
write_connect_msg(vntsd_client_t * clientp,char * group_name,char * domain_name)761ae08745Sheppo write_connect_msg(vntsd_client_t *clientp, char *group_name,
771ae08745Sheppo     char *domain_name)
781ae08745Sheppo {
791ae08745Sheppo 
801ae08745Sheppo 	int	rv = VNTSD_SUCCESS;
811ae08745Sheppo 	char	buf[VNTSD_LINE_LEN];
821ae08745Sheppo 
831ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) !=
841ae08745Sheppo 	    VNTSD_SUCCESS) {
851ae08745Sheppo 		return (rv);
861ae08745Sheppo 	}
871ae08745Sheppo 
881ae08745Sheppo 	(void) snprintf(buf, sizeof (buf),
891ae08745Sheppo 	    gettext("Connecting to console \"%s\" in group \"%s\" ...."),
901ae08745Sheppo 	    domain_name, group_name);
911ae08745Sheppo 
921ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) {
931ae08745Sheppo 		return (rv);
941ae08745Sheppo 	}
951ae08745Sheppo 
961ae08745Sheppo 	if ((rv = vntsd_write_line(clientp,
97*476d5ff7SToomas Soome 	    gettext("Press ~? for control options .."))) != VNTSD_SUCCESS) {
981ae08745Sheppo 		return (rv);
991ae08745Sheppo 	}
1001ae08745Sheppo 
1011ae08745Sheppo 	return (VNTSD_SUCCESS);
1021ae08745Sheppo }
1031ae08745Sheppo 
1041ae08745Sheppo static int
create_write_thread(vntsd_cons_t * consp)1051ae08745Sheppo create_write_thread(vntsd_cons_t *consp)
1061ae08745Sheppo {
1071ae08745Sheppo 
1081ae08745Sheppo 	assert(consp);
1091ae08745Sheppo 
1101ae08745Sheppo 	/* create write thread for the console */
1111ae08745Sheppo 	(void) mutex_lock(&consp->lock);
1121ae08745Sheppo 	if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread,
113*476d5ff7SToomas Soome 	    (void *)consp, 0, &consp->wr_tid)) {
1141ae08745Sheppo 
1151ae08745Sheppo 		DERR(stderr, "t@%d create_rd_wr_thread@%d: "
1161ae08745Sheppo 		    "create write thread failed\n",
1171ae08745Sheppo 		    thr_self(), consp->cons_no);
1181ae08745Sheppo 		(void) close(consp->vcc_fd);
1191ae08745Sheppo 		consp->vcc_fd = -1;
1201ae08745Sheppo 		(void) mutex_unlock(&consp->lock);
1211ae08745Sheppo 
1221ae08745Sheppo 		return (VNTSD_ERR_CREATE_WR_THR);
1231ae08745Sheppo 	}
1241ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
1251ae08745Sheppo 	return (VNTSD_SUCCESS);
1261ae08745Sheppo }
1271ae08745Sheppo 
1281ae08745Sheppo /* Display all domain consoles in a group. */
1291ae08745Sheppo static int
list_all_domains(vntsd_group_t * groupp,vntsd_client_t * clientp)1301ae08745Sheppo list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp)
1311ae08745Sheppo {
1321ae08745Sheppo 	char	    vntsd_line[VNTSD_LINE_LEN];
1331ae08745Sheppo 	int	    rv = VNTSD_SUCCESS;
1341ae08745Sheppo 
1351ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
1361ae08745Sheppo 	    != VNTSD_SUCCESS) {
1371ae08745Sheppo 		return (rv);
1381ae08745Sheppo 	}
1391ae08745Sheppo 
1401ae08745Sheppo 	/*
1411ae08745Sheppo 	 * TRANSLATION_NOTE
1421ae08745Sheppo 	 * The following three strings of the form "DOMAIN .." are table
1431ae08745Sheppo 	 * headers and should be all uppercase.
1441ae08745Sheppo 	 */
1451ae08745Sheppo 	(void) snprintf(vntsd_line, sizeof (vntsd_line),
1461ae08745Sheppo 	    "%-20s%-30s%-25s",
1471ae08745Sheppo 	    gettext("DOMAIN ID"), gettext("DOMAIN NAME"),
1481ae08745Sheppo 	    gettext("DOMAIN STATE"));
1491ae08745Sheppo 
1501ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, vntsd_line)) != VNTSD_SUCCESS) {
1511ae08745Sheppo 		return (rv);
1521ae08745Sheppo 	}
1531ae08745Sheppo 
1541ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
1551ae08745Sheppo 
1561ae08745Sheppo 	if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name,
157*476d5ff7SToomas Soome 	    &(clientp->sockfd)) != NULL) {
1581ae08745Sheppo 		rv = VNTSD_ERR_WRITE_CLIENT;
1591ae08745Sheppo 	}
1601ae08745Sheppo 
1611ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
1621ae08745Sheppo 
1631ae08745Sheppo 	return (rv);
1641ae08745Sheppo }
1651ae08745Sheppo 
1661ae08745Sheppo /* display help */
1671ae08745Sheppo static int
display_help(vntsd_client_t * clientp)1681ae08745Sheppo display_help(vntsd_client_t *clientp)
1691ae08745Sheppo {
1701ae08745Sheppo 	int	rv = VNTSD_SUCCESS;
1711ae08745Sheppo 	char	*bufp;
1721ae08745Sheppo 
173*476d5ff7SToomas Soome 	rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN);
174*476d5ff7SToomas Soome 	if (rv != VNTSD_SUCCESS) {
1751ae08745Sheppo 		return (rv);
1761ae08745Sheppo 	}
1771ae08745Sheppo 
1781ae08745Sheppo 	/*
1791ae08745Sheppo 	 * TRANSLATION_NOTE
1801ae08745Sheppo 	 * The following three strings of the form ". -- ..." are help
1811ae08745Sheppo 	 * messages for single character commands. Do not translate the
1821ae08745Sheppo 	 * character before the --.
1831ae08745Sheppo 	 */
1848e6a2a04Slm 	bufp = gettext("h -- this help");
1851ae08745Sheppo 
1861ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
1871ae08745Sheppo 		return (rv);
1881ae08745Sheppo 	}
1891ae08745Sheppo 
1901ae08745Sheppo 	bufp = gettext("l -- list of consoles");
1911ae08745Sheppo 
1921ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
1931ae08745Sheppo 		return (rv);
1941ae08745Sheppo 	}
1951ae08745Sheppo 
1961ae08745Sheppo 	bufp = gettext("q -- quit");
1971ae08745Sheppo 
1981ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
1991ae08745Sheppo 		return (rv);
2001ae08745Sheppo 	}
2011ae08745Sheppo 
2021ae08745Sheppo 	/*
2031ae08745Sheppo 	 * TRANSLATION_NOTE
2041ae08745Sheppo 	 * In the following string, "id" is a short mnemonic for
2051ae08745Sheppo 	 * "identifier" and both occurrences should be translated.
2061ae08745Sheppo 	 */
2071ae08745Sheppo 
2088e6a2a04Slm 	bufp = gettext("c{id}, n{name} -- connect to a console of domain {id}"
209*476d5ff7SToomas Soome 	    " or domain {name}");
2101ae08745Sheppo 
2111ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
2121ae08745Sheppo 		return (rv);
2131ae08745Sheppo 	}
2141ae08745Sheppo 
2151ae08745Sheppo 	return (VNTSD_SUCCESS);
2161ae08745Sheppo }
2171ae08745Sheppo 
2188e6a2a04Slm /* cons_by_name() - find a console structure according to  a ldom's name */
2198e6a2a04Slm static boolean_t
cons_by_name(vntsd_cons_t * consp,char * name)2208e6a2a04Slm cons_by_name(vntsd_cons_t *consp, char *name)
2218e6a2a04Slm {
2228e6a2a04Slm 	if (consp->status & VNTSD_CONS_DELETED) {
2238e6a2a04Slm 		return (B_FALSE);
2248e6a2a04Slm 	}
2258e6a2a04Slm 	return (strcmp(consp->domain_name, name) == 0);
2268e6a2a04Slm }
2278e6a2a04Slm 
2288e6a2a04Slm /* name_to_cons_no - convert a ldom's name to its consno */
2298e6a2a04Slm static int
name_to_cons_no(vntsd_group_t * groupp,char * name)2308e6a2a04Slm name_to_cons_no(vntsd_group_t *groupp, char *name)
2318e6a2a04Slm {
2328e6a2a04Slm 	vntsd_cons_t *consp;
2338e6a2a04Slm 
2348e6a2a04Slm 	consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq,
235*476d5ff7SToomas Soome 	    (compare_func_t)cons_by_name, name);
2368e6a2a04Slm 
2378e6a2a04Slm 	if (consp == NULL) {
2388e6a2a04Slm 		return (-1);
2398e6a2a04Slm 	}
2408e6a2a04Slm 
2418e6a2a04Slm 	return (consp->cons_no);
2428e6a2a04Slm }
2438e6a2a04Slm 
2441ae08745Sheppo /* select a console to connect */
2451ae08745Sheppo static int
select_cons(vntsd_group_t * groupp,vntsd_cons_t ** consp,vntsd_client_t * clientp,char c)2468e6a2a04Slm select_cons(vntsd_group_t *groupp, vntsd_cons_t **consp,
2471ae08745Sheppo     vntsd_client_t *clientp, char c)
2481ae08745Sheppo {
2498e6a2a04Slm 	int	    cons_no = -1;
2501ae08745Sheppo 	int	    n;
2511ae08745Sheppo 	int	    i;
2521ae08745Sheppo 	char	    buf[VNTSD_LINE_LEN];
2531ae08745Sheppo 	int	    rv;
2541ae08745Sheppo 
2551ae08745Sheppo 
2561ae08745Sheppo 
2571ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
2581ae08745Sheppo 	if (groupp->num_cons == 0) {
2591ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
2601ae08745Sheppo 		/* no console in this group */
2611ae08745Sheppo 		return (VNTSD_STATUS_NO_CONS);
2621ae08745Sheppo 	}
2631ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
2641ae08745Sheppo 
2651ae08745Sheppo 
2668e6a2a04Slm 	/* c{id} or n{name} */
2671ae08745Sheppo 
2681ae08745Sheppo 	n = VNTSD_LINE_LEN;
2691ae08745Sheppo 
2701ae08745Sheppo 	if ((rv = vntsd_read_line(clientp, buf, &n)) != VNTSD_SUCCESS) {
2711ae08745Sheppo 		return (rv);
2721ae08745Sheppo 	}
2731ae08745Sheppo 
2741ae08745Sheppo 	/* parse command */
2751ae08745Sheppo 	for (i = 0; i < n; i++) {
2768e6a2a04Slm 		switch (c) {
2778e6a2a04Slm 
2788e6a2a04Slm 		case 'c':
2798e6a2a04Slm 			/* c{id} or c {id} */
2808e6a2a04Slm 			if (isspace(buf[i])) {
281*476d5ff7SToomas Soome 				continue;
2828e6a2a04Slm 			}
2838e6a2a04Slm 
2848e6a2a04Slm 			if (!isdigit(buf[i])) {
2858e6a2a04Slm 				return (VNTSD_ERR_INVALID_INPUT);
2868e6a2a04Slm 			}
2878e6a2a04Slm 
2881ae08745Sheppo 			cons_no = atoi(buf + i);
2891ae08745Sheppo 			break;
2901ae08745Sheppo 
2918e6a2a04Slm 		case 'n':
2928e6a2a04Slm 			/* n{name) or n {name} */
2938e6a2a04Slm 			if (isspace(buf[i])) {
294*476d5ff7SToomas Soome 				continue;
2958e6a2a04Slm 			}
2961ae08745Sheppo 
2978e6a2a04Slm 			buf[n-1] = 0;
2988e6a2a04Slm 			cons_no = name_to_cons_no(groupp, buf+i);
2991ae08745Sheppo 			break;
3008e6a2a04Slm 
3018e6a2a04Slm 		default:
3028e6a2a04Slm 			/* should never get here */
3031ae08745Sheppo 			return (VNTSD_ERR_INVALID_INPUT);
3048e6a2a04Slm 
3051ae08745Sheppo 		}
3068e6a2a04Slm 
3078e6a2a04Slm 		/* got user selection */
3088e6a2a04Slm 		break;
3091ae08745Sheppo 	}
3101ae08745Sheppo 
3111ae08745Sheppo 	if (cons_no < 0) {
3121ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
3131ae08745Sheppo 	}
3141ae08745Sheppo 
3151ae08745Sheppo 	/* get selected console */
3161ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
3171ae08745Sheppo 
3181ae08745Sheppo 	*consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq,
319*476d5ff7SToomas Soome 	    (compare_func_t)vntsd_cons_by_consno, &cons_no);
3201ae08745Sheppo 
3211ae08745Sheppo 	if (*consp == NULL) {
3221ae08745Sheppo 		/* during console selection, the console has been  deleted */
3231ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
3241ae08745Sheppo 
3251ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
3261ae08745Sheppo 	}
3271ae08745Sheppo 	if ((*consp)->status & VNTSD_CONS_DELETED) {
3281ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
3291ae08745Sheppo 	}
3301ae08745Sheppo 
3311ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
3321ae08745Sheppo 
3331ae08745Sheppo 	return (VNTSD_SUCCESS);
3341ae08745Sheppo }
3351ae08745Sheppo 
3361ae08745Sheppo /* compare if there is a match console in the gorup */
3371ae08745Sheppo static boolean_t
find_cons_in_group(vntsd_cons_t * consp_in_group,vntsd_cons_t * consp)3381ae08745Sheppo find_cons_in_group(vntsd_cons_t *consp_in_group, vntsd_cons_t *consp)
3391ae08745Sheppo {
3401ae08745Sheppo 	if (consp_in_group == consp) {
3411ae08745Sheppo 		return (B_TRUE);
3421ae08745Sheppo 	} else {
3431ae08745Sheppo 		return (B_FALSE);
3441ae08745Sheppo 	}
3451ae08745Sheppo }
3461ae08745Sheppo 
3471ae08745Sheppo /* connect a client to a console */
3481ae08745Sheppo static int
connect_cons(vntsd_cons_t * consp,vntsd_client_t * clientp)3491ae08745Sheppo connect_cons(vntsd_cons_t *consp, vntsd_client_t *clientp)
3501ae08745Sheppo {
3511ae08745Sheppo 	int	rv, rv1;
3521ae08745Sheppo 	vntsd_group_t *groupp;
3531ae08745Sheppo 
3541ae08745Sheppo 	assert(consp);
3551ae08745Sheppo 	groupp = consp->group;
3561ae08745Sheppo 	assert(groupp);
3571ae08745Sheppo 	assert(clientp);
3581ae08745Sheppo 
3591ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
3601ae08745Sheppo 
361