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
3611ae08745Sheppo /* check if console is valid */
3621ae08745Sheppo consp = vntsd_que_find(groupp->conspq,
3631ae08745Sheppo (compare_func_t)find_cons_in_group, consp);
3641ae08745Sheppo
3651ae08745Sheppo if (consp == NULL) {
3661ae08745Sheppo (void) mutex_unlock(&groupp->lock);
3671ae08745Sheppo return (VNTSD_STATUS_NO_CONS);
3681ae08745Sheppo }
3691ae08745Sheppo if (consp->status & VNTSD_CONS_DELETED) {
3701ae08745Sheppo (void) mutex_unlock(&groupp->lock);
3711ae08745Sheppo return (VNTSD_STATUS_NO_CONS);
3721ae08745Sheppo }
3731ae08745Sheppo
3741ae08745Sheppo (void) mutex_lock(&consp->lock);
3751ae08745Sheppo (void) mutex_lock(&clientp->lock);
3761ae08745Sheppo
3771ae08745Sheppo
3781ae08745Sheppo clientp->cons = consp;
3791ae08745Sheppo
3801ae08745Sheppo /* enable daemon cmd */
3811ae08745Sheppo clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD;
3821ae08745Sheppo
3837636cb21Slm if (consp->clientpq == NULL && consp->vcc_fd == -1) {
3847636cb21Slm
3857636cb21Slm /*
3867636cb21Slm * the first connection to a console - a writer
3877636cb21Slm * and the console has not opened.
3887636cb21Slm */
3891ae08745Sheppo consp->vcc_fd = vntsd_open_vcc(consp->dev_name, consp->cons_no);
3901ae08745Sheppo if (consp->vcc_fd < 0) {
3911ae08745Sheppo (void) mutex_unlock(&clientp->lock);
3921ae08745Sheppo (void) mutex_unlock(&consp->lock);
3931ae08745Sheppo (void) mutex_unlock(&groupp->lock);
3941ae08745Sheppo assert(consp->group);
3951ae08745Sheppo return (vntsd_vcc_err(consp));
3961ae08745Sheppo }
3971ae08745Sheppo }
3981ae08745Sheppo
3991ae08745Sheppo (void) mutex_unlock(&clientp->lock);
4001ae08745Sheppo
4011ae08745Sheppo /*
4021ae08745Sheppo * move the client from group's no console selected queue
4031ae08745Sheppo * to cons queue
4041ae08745Sheppo */
4051ae08745Sheppo
4061ae08745Sheppo rv = vntsd_que_rm(&groupp->no_cons_clientpq, clientp);
4071ae08745Sheppo assert(rv == VNTSD_SUCCESS);
4081ae08745Sheppo
4091ae08745Sheppo rv = vntsd_que_append(&consp->clientpq, clientp);
4101ae08745Sheppo (void) mutex_unlock(&groupp->lock);
4111ae08745Sheppo
4121ae08745Sheppo if (rv != VNTSD_SUCCESS) {
4131ae08745Sheppo if (consp->clientpq->handle == clientp) {
4141ae08745Sheppo /* writer */
4151ae08745Sheppo (void) close(consp->vcc_fd);
4161ae08745Sheppo consp->vcc_fd = -1;
4171ae08745Sheppo }
4181ae08745Sheppo
4191ae08745Sheppo (void) mutex_unlock(&consp->lock);
4201ae08745Sheppo return (rv);
4211ae08745Sheppo }
4221ae08745Sheppo
4231ae08745Sheppo (void) mutex_unlock(&consp->lock);
4241ae08745Sheppo
4251ae08745Sheppo if (consp->clientpq->handle == clientp) {
4261ae08745Sheppo /* create a write thread */
4271ae08745Sheppo rv = create_write_thread(consp);
4281ae08745Sheppo if (rv != VNTSD_SUCCESS) {
4291ae08745Sheppo return (rv);
4301ae08745Sheppo }
4311ae08745Sheppo }
4321ae08745Sheppo
4331ae08745Sheppo /* write connecting message */
4341ae08745Sheppo if ((rv = write_connect_msg(clientp, consp->group->group_name,
4351ae08745Sheppo consp->domain_name)) != VNTSD_SUCCESS) {
4361ae08745Sheppo return (rv);
4371ae08745Sheppo }
4381ae08745Sheppo
4391ae08745Sheppo /* process input from client */
4401ae08745Sheppo rv = vntsd_read(clientp);
4411ae08745Sheppo
4421ae08745Sheppo /* client disconnected from the console */
4431ae08745Sheppo (void) mutex_lock(&groupp->lock);
4441ae08745Sheppo
4451ae08745Sheppo /* remove client from console queue */
4461ae08745Sheppo (void) mutex_lock(&consp->lock);
4471ae08745Sheppo rv1 = vntsd_que_rm(&consp->clientpq, clientp);
4481ae08745Sheppo assert(rv1 == VNTSD_SUCCESS);
4491ae08745Sheppo
4501ae08745Sheppo /* append client to group's no console selected queue */
4511ae08745Sheppo rv1 = vntsd_que_append(&groupp->no_cons_clientpq, clientp);
4521ae08745Sheppo (void) mutex_unlock(&groupp->lock);
4531ae08745Sheppo
4541ae08745Sheppo if (consp->clientpq == NULL) {
4551ae08745Sheppo /* clean up console since there is no client connected to it */
4561ae08745Sheppo assert(consp->vcc_fd != -1);
4571ae08745Sheppo
4581ae08745Sheppo /* force write thread to exit */
4591ae08745Sheppo assert(consp->wr_tid != (thread_t)-1);
4601ae08745Sheppo (void) thr_kill(consp->wr_tid, SIGUSR1);
4611ae08745Sheppo (void) mutex_unlock(&consp->lock);
4621ae08745Sheppo (void) thr_join(consp->wr_tid, NULL, NULL);
4631ae08745Sheppo (void) mutex_lock(&consp->lock);
4641ae08745Sheppo }
4651ae08745Sheppo
4661ae08745Sheppo if (consp->status & VNTSD_CONS_SIG_WAIT) {
4671ae08745Sheppo /* console is waiting for client to disconnect */
4681ae08745Sheppo (void) cond_signal(&consp->cvp);
4691ae08745Sheppo }
4701ae08745Sheppo
4711ae08745Sheppo (void) mutex_unlock(&consp->lock);
4721ae08745Sheppo
4731ae08745Sheppo return (rv1 == VNTSD_SUCCESS ? rv : rv1);
4741ae08745Sheppo
4751ae08745Sheppo }
4761ae08745Sheppo
4771ae08745Sheppo /* read command line input */
4781ae08745Sheppo static int
read_cmd(vntsd_client_t * clientp,char * prompt,char * cmd)4791ae08745Sheppo read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd)
4801ae08745Sheppo {
4811ae08745Sheppo int rv;
4821ae08745Sheppo
4831ae08745Sheppo /* disable daemon special command */
4841ae08745Sheppo (void) mutex_lock(&clientp->lock);
4851ae08745Sheppo clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD;
4861ae08745Sheppo (void) mutex_unlock(&clientp->lock);
4871ae08745Sheppo
488*476d5ff7SToomas Soome rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN);
489*476d5ff7SToomas Soome if (rv != VNTSD_SUCCESS) {
4901ae08745Sheppo return (rv);
4911ae08745Sheppo }
4921ae08745Sheppo
493*476d5ff7SToomas Soome rv = vntsd_write_client(clientp, prompt, strlen(prompt));
494*476d5ff7SToomas Soome if (rv != VNTSD_SUCCESS) {
4951ae08745Sheppo return (rv);
4961ae08745Sheppo }
4971ae08745Sheppo
4981ae08745Sheppo if ((rv = vntsd_read_data(clientp, cmd)) != VNTSD_SUCCESS) {
4991ae08745Sheppo return (rv);
5001ae08745Sheppo }
5011ae08745Sheppo if (*cmd == BS) {
5021ae08745Sheppo return (VNTSD_SUCCESS);
5031ae08745Sheppo }
5041ae08745Sheppo
5051ae08745Sheppo rv = vntsd_write_client(clientp, cmd, 1);
5061ae08745Sheppo
5071ae08745Sheppo *cmd = tolower(*cmd);
5081ae08745Sheppo
5091ae08745Sheppo return (rv);
5101ae08745Sheppo }
5111ae08745Sheppo
5121ae08745Sheppo /* reset client for selecting a console in the group */
5131ae08745Sheppo static void
client_init(vntsd_client_t * clientp)5141ae08745Sheppo client_init(vntsd_client_t *clientp)
5151ae08745Sheppo {
5161ae08745Sheppo (void) mutex_lock(&clientp->lock);
5171ae08745Sheppo clientp->cons = NULL;
5181ae08745Sheppo clientp->status = 0;
5191ae08745Sheppo (void) mutex_unlock(&clientp->lock);
5201ae08745Sheppo }
5217636cb21Slm /* is there any connection to a given console? */
5227636cb21Slm static boolean_t
is_client_que_empty(vntsd_cons_t * consp)5237636cb21Slm is_client_que_empty(vntsd_cons_t *consp)
5247636cb21Slm {
5257636cb21Slm boolean_t has_client = B_FALSE;
5267636cb21Slm
5277636cb21Slm (void) mutex_lock(&consp->lock);
5287636cb21Slm
5297636cb21Slm if (consp->clientpq != NULL)
5307636cb21Slm has_client = B_TRUE;
5317636cb21Slm
5327636cb21Slm (void) mutex_unlock(&consp->lock);
5337636cb21Slm
5347636cb21Slm return (has_client);
5357636cb21Slm }
5367636cb21Slm
5377636cb21Slm /*
5387636cb21Slm * close one opened console.
5397636cb21Slm * This function is passed to vntsd_que_walk to close one console.
5407636cb21Slm * The function returns B_FALSE so that vntsd_que_walk will
5417636cb21Slm * continue to apply the function to all consoles in the group.
5427636cb21Slm */
5437636cb21Slm static boolean_t
close_one_vcc_fd(vntsd_cons_t * consp)5447636cb21Slm close_one_vcc_fd(vntsd_cons_t *consp)
5457636cb21Slm {
5467636cb21Slm (void) mutex_lock(&consp->lock);
5477636cb21Slm
5487636cb21Slm if (consp->vcc_fd != -1) {
5497636cb21Slm (void) close(consp->vcc_fd);
5507636cb21Slm consp->vcc_fd = -1;
5517636cb21Slm }
5527636cb21Slm
5537636cb21Slm (void) mutex_unlock(&consp->lock);
5547636cb21Slm
5557636cb21Slm return (B_FALSE);
5567636cb21Slm }
5577636cb21Slm
5581ae08745Sheppo
5591ae08745Sheppo /* clean up client and exit the thread */
5601ae08745Sheppo static void
client_fini(vntsd_group_t * groupp,vntsd_client_t * clientp)5611ae08745Sheppo client_fini(vntsd_group_t *groupp, vntsd_client_t *clientp)
5621ae08745Sheppo {
5631ae08745Sheppo
5641ae08745Sheppo assert(groupp);
5651ae08745Sheppo assert(clientp);
5661ae08745Sheppo
5671ae08745Sheppo /* disconnct client from tcp port */
5681ae08745Sheppo assert(clientp->sockfd != -1);
5691ae08745Sheppo (void) close(clientp->sockfd);
5701ae08745Sheppo
5711ae08745Sheppo (void) mutex_lock(&groupp->lock);
5727636cb21Slm
5737636cb21Slm /*
5747636cb21Slm * close all consoles in the group if the client is the
5757636cb21Slm * last one connected to the group
5767636cb21Slm */
5777636cb21Slm if (vntsd_que_walk(groupp->conspq, (el_func_t)is_client_que_empty) ==
5787636cb21Slm VNTSD_SUCCESS) {
5797636cb21Slm (void) vntsd_que_walk(groupp->conspq,
5807636cb21Slm (el_func_t)close_one_vcc_fd);
5817636cb21Slm }
5827636cb21Slm
5837636cb21Slm
5841ae08745Sheppo (void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp);
5851ae08745Sheppo
5861ae08745Sheppo if ((groupp->no_cons_clientpq == NULL) &&
5871ae08745Sheppo (groupp->status & VNTSD_GROUP_SIG_WAIT)) {
5884d39be2bSsg /*
5894d39be2bSsg * group is waiting to be deleted. - signal the group's
5904d39be2bSsg * listen thread - the VNTSD_GROUP_SIG_WAIT state will
5914d39be2bSsg * be cleared when the listen thread exits.
5924d39be2bSsg */
5931ae08745Sheppo (void) cond_signal(&groupp->cvp);
5941ae08745Sheppo }
5951ae08745Sheppo (void) mutex_unlock(&groupp->lock);
5961ae08745Sheppo
5971ae08745Sheppo (void) mutex_destroy(&clientp->lock);
5981ae08745Sheppo free(clientp);
5991ae08745Sheppo
6001ae08745Sheppo thr_exit(0);
6011ae08745Sheppo }
6021ae08745Sheppo
6031ae08745Sheppo /* check client's status. exit if client quits or fatal errors */
6041ae08745Sheppo static void
console_chk_status(vntsd_group_t * groupp,vntsd_client_t * clientp,int status)6051ae08745Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status)
6061ae08745Sheppo {
6071ae08745Sheppo char err_msg[VNTSD_LINE_LEN];
6081ae08745Sheppo
6091ae08745Sheppo D1(stderr, "t@%d console_chk_status() status=%d "
6101ae08745Sheppo "client status=%x num consoles=%d \n",
6111ae08745Sheppo thr_self(), status, clientp->status, groupp->num_cons);
6121ae08745Sheppo
6131ae08745Sheppo (void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d"
6141ae08745Sheppo " num_cos=%d", clientp->sockfd, groupp->num_cons);
6151ae08745Sheppo
6164d39be2bSsg /*
6174d39be2bSsg * obtain group lock to protect groupp->num_cons.
6184d39be2bSsg * When groupp->num_cons == 0, close client and exit the tread.
6194d39be2bSsg */
6204d39be2bSsg (void) mutex_lock(&groupp->lock);
6214d39be2bSsg
6221ae08745Sheppo if (groupp->num_cons == 0) {
6231ae08745Sheppo /* no more console in the group */
6244d39be2bSsg (void) mutex_unlock(&groupp->lock);
6251ae08745Sheppo client_fini(groupp, clientp);
6264d39be2bSsg return;
6271ae08745Sheppo }
6281ae08745Sheppo
6291ae08745Sheppo if (status == VNTSD_STATUS_INTR) {
6301ae08745Sheppo /* reason for signal? */
6311ae08745Sheppo status = vntsd_cons_chk_intr(clientp);
6321ae08745Sheppo }
6331ae08745Sheppo
6341ae08745Sheppo switch (status) {
6351ae08745Sheppo
6361ae08745Sheppo case VNTSD_STATUS_CLIENT_QUIT:
6374d39be2bSsg (void) mutex_unlock(&groupp->lock);
6381ae08745Sheppo client_fini(groupp, clientp);
6391ae08745Sheppo return;
6401ae08745Sheppo
6411ae08745Sheppo case VNTSD_STATUS_RESELECT_CONS:
6424d39be2bSsg
6434d39be2bSsg if (clientp->cons == NULL) {
6444d39be2bSsg /*
6454d39be2bSsg * domain was deleted before client connects to it
6464d39be2bSsg * connect to other console in the same group
6474d39be2bSsg */
6484d39be2bSsg (void) mutex_unlock(&groupp->lock);
6494d39be2bSsg client_init(clientp);
6504d39be2bSsg return;
6514d39be2bSsg }
6524d39be2bSsg
6531ae08745Sheppo if ((groupp->num_cons == 1) &&
6544d39be2bSsg ((clientp->status & VNTSD_CLIENT_CONS_DELETED) ||
6554d39be2bSsg (groupp->conspq->handle == clientp->cons))) {
6561ae08745Sheppo /* no other selection available */
6574d39be2bSsg (void) mutex_unlock(&groupp->lock);
6581ae08745Sheppo client_fini(groupp, clientp);
6591ae08745Sheppo } else {
6604d39be2bSsg (void) mutex_unlock(&groupp->lock);
6611ae08745Sheppo client_init(clientp);
6621ae08745Sheppo }
6634d39be2bSsg
6641ae08745Sheppo return;
6651ae08745Sheppo
6661ae08745Sheppo case VNTSD_STATUS_VCC_IO_ERR:
6671ae08745Sheppo if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) {
6681ae08745Sheppo /* check if console was deleted */
6694d39be2bSsg (void) mutex_unlock(&groupp->lock);
6701ae08745Sheppo status = vntsd_vcc_err(clientp->cons);
6714d39be2bSsg (void) mutex_lock(&groupp->lock);
6721ae08745Sheppo }
6731ae08745Sheppo
6741ae08745Sheppo if (status != VNTSD_STATUS_CONTINUE) {
6751ae08745Sheppo /* console was deleted */
6764d39be2bSsg if (groupp->num_cons <= 1) {
6774d39be2bSsg (void) mutex_unlock(&groupp->lock);
6781ae08745Sheppo client_fini(groupp, clientp);
6794d39be2bSsg return;
6801ae08745Sheppo }
6811ae08745Sheppo }
6821ae08745Sheppo
6834d39be2bSsg (void) mutex_unlock(&groupp->lock);
6841ae08745Sheppo /* console is ok */
6851ae08745Sheppo client_init(clientp);
6861ae08745Sheppo return;
6871ae08745Sheppo
6881ae08745Sheppo case VNTSD_STATUS_MOV_CONS_FORWARD:
6891ae08745Sheppo case VNTSD_STATUS_MOV_CONS_BACKWARD:
6901ae08745Sheppo if (groupp->num_cons == 1) {
6911ae08745Sheppo /* same console */
6924d39be2bSsg (void) mutex_unlock(&groupp->lock);
6931ae08745Sheppo return;
6941ae08745Sheppo }
6951ae08745Sheppo
6961ae08745Sheppo /* get selected console */
6974d39be2bSsg clientp->cons = vntsd_que_pos(groupp->conspq,
6981ae08745Sheppo clientp->cons,
6991ae08745Sheppo (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1));
7004d39be2bSsg (void) mutex_unlock(&groupp->lock);
7011ae08745Sheppo return;
7021ae08745Sheppo
7031ae08745Sheppo case VNTSD_SUCCESS:
7041ae08745Sheppo case VNTSD_STATUS_CONTINUE:
7054d39be2bSsg (void) mutex_unlock(&groupp->lock);
7061ae08745Sheppo client_init(clientp);
7071ae08745Sheppo return;
7081ae08745Sheppo
7093c96341aSnarayan
7103c96341aSnarayan case VNTSD_STATUS_NO_CONS:
7113c96341aSnarayan /*
7123c96341aSnarayan * there are two cases when the status is VNTSD_SATATUS_NO_CONS.
7133c96341aSnarayan * case 1. the console was removed but there is at least one
7143c96341aSnarayan * another console in the group that client can connect to.
7153c96341aSnarayan * case 2. there is no console in the group. Client needs to
7163c96341aSnarayan * be disconnected from vntsd.
7173c96341aSnarayan */
7183c96341aSnarayan if (groupp->num_cons == 0) {
7193c96341aSnarayan (void) mutex_unlock(&groupp->lock);
7203c96341aSnarayan client_fini(groupp, clientp);
7213c96341aSnarayan } else {
7223c96341aSnarayan (void) mutex_unlock(&groupp->lock);
7233c96341aSnarayan client_init(clientp);
7243c96341aSnarayan }
7253c96341aSnarayan return;
7263c96341aSnarayan
7273c96341aSnarayan
7281ae08745Sheppo case VNTSD_ERR_INVALID_INPUT:
7294d39be2bSsg (void) mutex_unlock(&groupp->lock);
7301ae08745Sheppo return;
7311ae08745Sheppo
7321ae08745Sheppo default:
7331ae08745Sheppo /* fatal error */
7344d39be2bSsg (void) mutex_unlock(&groupp->lock);
7351ae08745Sheppo vntsd_log(status, err_msg);
7361ae08745Sheppo client_fini(groupp, clientp);
7371ae08745Sheppo return;
7381ae08745Sheppo }
7391ae08745Sheppo }
7401ae08745Sheppo
7411ae08745Sheppo /* console thread */
7421ae08745Sheppo void *
vntsd_console_thread(vntsd_thr_arg_t * argp)7431ae08745Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp)
7441ae08745Sheppo {
7451ae08745Sheppo vntsd_group_t *groupp;
7461ae08745Sheppo vntsd_cons_t *consp;
7471ae08745Sheppo vntsd_client_t *clientp;
7481ae08745Sheppo
7491ae08745Sheppo char buf[MAXHOSTNAMELEN];
7501ae08745Sheppo char prompt[72];
7511ae08745Sheppo char cmd;
7521ae08745Sheppo int rv = VNTSD_SUCCESS;
7531ae08745Sheppo int num_cons;
7541ae08745Sheppo
7551ae08745Sheppo
7561ae08745Sheppo groupp = (vntsd_group_t *)argp->handle;
7571ae08745Sheppo clientp = (vntsd_client_t *)argp->arg;
7581ae08745Sheppo
7591ae08745Sheppo assert(groupp);
7601ae08745Sheppo assert(clientp);
7611ae08745Sheppo
7623c96341aSnarayan /* free argp, which was allocated in listen thread */
7633c96341aSnarayan free(argp);
7643c96341aSnarayan
7651ae08745Sheppo /* check if group is removed */
7661ae08745Sheppo
7671ae08745Sheppo D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(),
7681ae08745Sheppo groupp->tcp_port, clientp->sockfd);
7691ae08745Sheppo
7701ae08745Sheppo bzero(buf, MAXHOSTNAMELEN);
7711ae08745Sheppo
7721ae08745Sheppo /* host name */
7731ae08745Sheppo if (gethostname(buf, MAXHOSTNAMELEN)) {
7741ae08745Sheppo vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()");
7751ae08745Sheppo (void) snprintf(buf, sizeof (buf), "unkown host");
7761ae08745Sheppo }
7771ae08745Sheppo
7781ae08745Sheppo if (snprintf(prompt, sizeof (prompt),
779*476d5ff7SToomas Soome "%s-vnts-%s: h, l, c{id}, n{name}, q:",
7801ae08745Sheppo buf, groupp->group_name) >= sizeof (prompt)) {
7811ae08745Sheppo /* long prompt doesn't fit, use short one */
7821ae08745Sheppo (void) snprintf(prompt, sizeof (prompt),
783*476d5ff7SToomas Soome "vnts: h, l, c{id}, n{name}, q:");
7841ae08745Sheppo }
7851ae08745Sheppo
7861ae08745Sheppo
7871ae08745Sheppo for (;;) {
7881ae08745Sheppo cmd = ' ';
7891ae08745Sheppo D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(),
7901ae08745Sheppo groupp->tcp_port, clientp->sockfd);
7911ae08745Sheppo
7921ae08745Sheppo num_cons = vntsd_chk_group_total_cons(groupp);
7931ae08745Sheppo
7941ae08745Sheppo if ((num_cons > 1) && (clientp->cons == NULL)) {
7951ae08745Sheppo /* console to connect to */
7961ae08745Sheppo rv = read_cmd(clientp, prompt, &cmd);
7971ae08745Sheppo /* check error and may exit */
7981ae08745Sheppo console_chk_status(groupp, clientp, rv);
7994d39be2bSsg
8004d39be2bSsg /* any console is removed from group? */
8014d39be2bSsg num_cons = vntsd_chk_group_total_cons(groupp);
8024d39be2bSsg if (num_cons <= 1) {
8034d39be2bSsg cmd = ' ';
8044d39be2bSsg }
8051ae08745Sheppo }
8061ae08745Sheppo
8071ae08745Sheppo switch (cmd) {
8081ae08745Sheppo
8091ae08745Sheppo case 'l':
8101ae08745Sheppo
8111ae08745Sheppo /* list domain names */
8121ae08745Sheppo rv = list_all_domains(groupp, clientp);
8131ae08745Sheppo break;
8141ae08745Sheppo
8151ae08745Sheppo
8161ae08745Sheppo case 'q':
8171ae08745Sheppo
8181ae08745Sheppo rv = VNTSD_STATUS_CLIENT_QUIT;
8191ae08745Sheppo break;
8201ae08745Sheppo
8218e6a2a04Slm case ' ':
8228e6a2a04Slm
8233c96341aSnarayan if (num_cons == 0) {
8244d39be2bSsg /* no console in the group */
8253c96341aSnarayan rv = VNTSD_STATUS_NO_CONS;
8264d39be2bSsg break;
8273c96341aSnarayan }
8284d39be2bSsg
8298e6a2a04Slm if (clientp->cons == NULL) {
8308e6a2a04Slm if (num_cons == 1) {
8318e6a2a04Slm /* by pass selecting console */
8328e6a2a04Slm consp = (vntsd_cons_t *)
8338e6a2a04Slm (groupp->conspq->handle);
8348e6a2a04Slm } else {
8358e6a2a04Slm continue;
8368e6a2a04Slm }
8378e6a2a04Slm
8388e6a2a04Slm } else {
8398e6a2a04Slm consp = clientp->cons;
8408e6a2a04Slm }
8418e6a2a04Slm
8428e6a2a04Slm /* connect to console */
8438e6a2a04Slm rv = connect_cons(consp, clientp);
8448e6a2a04Slm
8451ae08745Sheppo break;
8461ae08745Sheppo
8478e6a2a04Slm case 'c':
8488e6a2a04Slm case 'n':
8491ae08745Sheppo /* select console */
8501ae08745Sheppo if (clientp->cons == NULL) {
8518e6a2a04Slm rv = select_cons(groupp, &consp, clientp, cmd);
8521ae08745Sheppo if (rv == VNTSD_ERR_INVALID_INPUT) {
8531ae08745Sheppo rv = display_help(clientp);
8541ae08745Sheppo break;
8551ae08745Sheppo }
8563c96341aSnarayan
8573c96341aSnarayan /*
8583c96341aSnarayan * all consoles in the group
8593c96341aSnarayan * may be gone before this client
8603c96341aSnarayan * could select one.
8613c96341aSnarayan */
8623c96341aSnarayan if (rv != VNTSD_SUCCESS)
8633c96341aSnarayan break;
8643c96341aSnarayan
8651ae08745Sheppo } else {
8661ae08745Sheppo consp = clientp->cons;
8671ae08745Sheppo }
8681ae08745Sheppo assert(consp);
8691ae08745Sheppo
8701ae08745Sheppo /* connect to console */
8711ae08745Sheppo rv = connect_cons(consp, clientp);
8721ae08745Sheppo D1(stderr, "t@%d console_thread()"
8731ae08745Sheppo "connect_cons returns %d\n",
8741ae08745Sheppo thr_self(), rv);
8751ae08745Sheppo break;
8761ae08745Sheppo
8778e6a2a04Slm case 'h':
8788e6a2a04Slm default:
8798e6a2a04Slm rv = display_help(clientp);
8808e6a2a04Slm break;
8818e6a2a04Slm
8821ae08745Sheppo }
8838e6a2a04Slm
8841ae08745Sheppo /* check error and may exit */
8851ae08745Sheppo console_chk_status(groupp, clientp, rv);
8861ae08745Sheppo }
8871ae08745Sheppo
8881ae08745Sheppo /*NOTREACHED*/
8891ae08745Sheppo return (NULL);
8901ae08745Sheppo }
891