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 /*
22*3401Snarayan * Copyright 2007 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
display_domain_name(vntsd_cons_t * consp,int * fd)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
write_connect_msg(vntsd_client_t * clientp,char * group_name,char * domain_name)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
create_write_thread(vntsd_cons_t * consp)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
list_all_domains(vntsd_group_t * groupp,vntsd_client_t * clientp)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
display_help(vntsd_client_t * clientp)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
cons_by_name(vntsd_cons_t * consp,char * name)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
name_to_cons_no(vntsd_group_t * groupp,char * name)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
select_cons(vntsd_group_t * groupp,vntsd_cons_t ** consp,vntsd_client_t * clientp,char c)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
find_cons_in_group(vntsd_cons_t * consp_in_group,vntsd_cons_t * consp)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
connect_cons(vntsd_cons_t * consp,vntsd_client_t * clientp)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
3852748Slm66018 if (consp->clientpq == NULL && consp->vcc_fd == -1) {
3862748Slm66018
3872748Slm66018 /*
3882748Slm66018 * the first connection to a console - a writer
3892748Slm66018 * and the console has not opened.
3902748Slm66018 */
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
read_cmd(vntsd_client_t * clientp,char * prompt,char * cmd)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
client_init(vntsd_client_t * clientp)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 }
5232748Slm66018 /* is there any connection to a given console? */
5242748Slm66018 static boolean_t
is_client_que_empty(vntsd_cons_t * consp)5252748Slm66018 is_client_que_empty(vntsd_cons_t *consp)
5262748Slm66018 {
5272748Slm66018 boolean_t has_client = B_FALSE;
5282748Slm66018
5292748Slm66018 (void) mutex_lock(&consp->lock);
5302748Slm66018
5312748Slm66018 if (consp->clientpq != NULL)
5322748Slm66018 has_client = B_TRUE;
5332748Slm66018
5342748Slm66018 (void) mutex_unlock(&consp->lock);
5352748Slm66018
5362748Slm66018 return (has_client);
5372748Slm66018 }
5382748Slm66018
5392748Slm66018 /*
5402748Slm66018 * close one opened console.
5412748Slm66018 * This function is passed to vntsd_que_walk to close one console.
5422748Slm66018 * The function returns B_FALSE so that vntsd_que_walk will
5432748Slm66018 * continue to apply the function to all consoles in the group.
5442748Slm66018 */
5452748Slm66018 static boolean_t
close_one_vcc_fd(vntsd_cons_t * consp)5462748Slm66018 close_one_vcc_fd(vntsd_cons_t *consp)
5472748Slm66018 {
5482748Slm66018 (void) mutex_lock(&consp->lock);
5492748Slm66018
5502748Slm66018 if (consp->vcc_fd != -1) {
5512748Slm66018 (void) close(consp->vcc_fd);
5522748Slm66018 consp->vcc_fd = -1;
5532748Slm66018 }
5542748Slm66018
5552748Slm66018 (void) mutex_unlock(&consp->lock);
5562748Slm66018
5572748Slm66018 return (B_FALSE);
5582748Slm66018 }
5592748Slm66018
5601991Sheppo
5611991Sheppo /* clean up client and exit the thread */
5621991Sheppo static void
client_fini(vntsd_group_t * groupp,vntsd_client_t * clientp)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);
5742748Slm66018
5752748Slm66018 /*
5762748Slm66018 * close all consoles in the group if the client is the
5772748Slm66018 * last one connected to the group
5782748Slm66018 */
5792748Slm66018 if (vntsd_que_walk(groupp->conspq, (el_func_t)is_client_que_empty) ==
5802748Slm66018 VNTSD_SUCCESS) {
5812748Slm66018 (void) vntsd_que_walk(groupp->conspq,
5822748Slm66018 (el_func_t)close_one_vcc_fd);
5832748Slm66018 }
5842748Slm66018
5852748Slm66018
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)) {
5903151Ssg70180 /*
5913151Ssg70180 * group is waiting to be deleted. - signal the group's
5923151Ssg70180 * listen thread - the VNTSD_GROUP_SIG_WAIT state will
5933151Ssg70180 * be cleared when the listen thread exits.
5943151Ssg70180 */
5951991Sheppo (void) cond_signal(&groupp->cvp);
5961991Sheppo }
5971991Sheppo (void) mutex_unlock(&groupp->lock);
5981991Sheppo
5991991Sheppo (void) mutex_destroy(&clientp->lock);
6001991Sheppo free(clientp);
6011991Sheppo
6021991Sheppo thr_exit(0);
6031991Sheppo }
6041991Sheppo
6051991Sheppo /* check client's status. exit if client quits or fatal errors */
6061991Sheppo static void
console_chk_status(vntsd_group_t * groupp,vntsd_client_t * clientp,int status)6071991Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status)
6081991Sheppo {
6091991Sheppo char err_msg[VNTSD_LINE_LEN];
6101991Sheppo
6111991Sheppo D1(stderr, "t@%d console_chk_status() status=%d "
6121991Sheppo "client status=%x num consoles=%d \n",
6131991Sheppo thr_self(), status, clientp->status, groupp->num_cons);
6141991Sheppo
6151991Sheppo (void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d"
6161991Sheppo " num_cos=%d", clientp->sockfd, groupp->num_cons);
6171991Sheppo
6183151Ssg70180 /*
6193151Ssg70180 * obtain group lock to protect groupp->num_cons.
6203151Ssg70180 * When groupp->num_cons == 0, close client and exit the tread.
6213151Ssg70180 */
6223151Ssg70180 (void) mutex_lock(&groupp->lock);
6233151Ssg70180
6241991Sheppo if (groupp->num_cons == 0) {
6251991Sheppo /* no more console in the group */
6263151Ssg70180 (void) mutex_unlock(&groupp->lock);
6271991Sheppo client_fini(groupp, clientp);
6283151Ssg70180 return;
6291991Sheppo }
6301991Sheppo
6311991Sheppo if (status == VNTSD_STATUS_INTR) {
6321991Sheppo /* reason for signal? */
6331991Sheppo status = vntsd_cons_chk_intr(clientp);
6341991Sheppo }
6351991Sheppo
6361991Sheppo switch (status) {
6371991Sheppo
6381991Sheppo case VNTSD_STATUS_CLIENT_QUIT:
6393151Ssg70180 (void) mutex_unlock(&groupp->lock);
6401991Sheppo client_fini(groupp, clientp);
6411991Sheppo return;
6421991Sheppo
6431991Sheppo case VNTSD_STATUS_RESELECT_CONS:
6443151Ssg70180
6453151Ssg70180 if (clientp->cons == NULL) {
6463151Ssg70180 /*
6473151Ssg70180 * domain was deleted before client connects to it
6483151Ssg70180 * connect to other console in the same group
6493151Ssg70180 */
6503151Ssg70180 (void) mutex_unlock(&groupp->lock);
6513151Ssg70180 client_init(clientp);
6523151Ssg70180 return;
6533151Ssg70180 }
6543151Ssg70180
6551991Sheppo if ((groupp->num_cons == 1) &&
6563151Ssg70180 ((clientp->status & VNTSD_CLIENT_CONS_DELETED) ||
6573151Ssg70180 (groupp->conspq->handle == clientp->cons))) {
6581991Sheppo /* no other selection available */
6593151Ssg70180 (void) mutex_unlock(&groupp->lock);
6601991Sheppo client_fini(groupp, clientp);
6611991Sheppo } else {
6623151Ssg70180 (void) mutex_unlock(&groupp->lock);
6631991Sheppo client_init(clientp);
6641991Sheppo }
6653151Ssg70180
6661991Sheppo return;
6671991Sheppo
6681991Sheppo case VNTSD_STATUS_VCC_IO_ERR:
6691991Sheppo if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) {
6701991Sheppo /* check if console was deleted */
6713151Ssg70180 (void) mutex_unlock(&groupp->lock);
6721991Sheppo status = vntsd_vcc_err(clientp->cons);
6733151Ssg70180 (void) mutex_lock(&groupp->lock);
6741991Sheppo }
6751991Sheppo
6761991Sheppo if (status != VNTSD_STATUS_CONTINUE) {
6771991Sheppo /* console was deleted */
6783151Ssg70180 if (groupp->num_cons <= 1) {
6793151Ssg70180 (void) mutex_unlock(&groupp->lock);
6801991Sheppo client_fini(groupp, clientp);
6813151Ssg70180 return;
6821991Sheppo }
6831991Sheppo }
6841991Sheppo
6853151Ssg70180 (void) mutex_unlock(&groupp->lock);
6861991Sheppo /* console is ok */
6871991Sheppo client_init(clientp);
6881991Sheppo return;
6891991Sheppo
6901991Sheppo case VNTSD_STATUS_MOV_CONS_FORWARD:
6911991Sheppo case VNTSD_STATUS_MOV_CONS_BACKWARD:
6921991Sheppo if (groupp->num_cons == 1) {
6931991Sheppo /* same console */
6943151Ssg70180 (void) mutex_unlock(&groupp->lock);
6951991Sheppo return;
6961991Sheppo }
6971991Sheppo
6981991Sheppo /* get selected console */
6993151Ssg70180 clientp->cons = vntsd_que_pos(groupp->conspq,
7001991Sheppo clientp->cons,
7011991Sheppo (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1));
7023151Ssg70180 (void) mutex_unlock(&groupp->lock);
7031991Sheppo return;
7041991Sheppo
7051991Sheppo case VNTSD_SUCCESS:
7061991Sheppo case VNTSD_STATUS_CONTINUE:
7073151Ssg70180 (void) mutex_unlock(&groupp->lock);
7081991Sheppo client_init(clientp);
7091991Sheppo return;
7101991Sheppo
711*3401Snarayan
712*3401Snarayan case VNTSD_STATUS_NO_CONS:
713*3401Snarayan /*
714*3401Snarayan * there are two cases when the status is VNTSD_SATATUS_NO_CONS.
715*3401Snarayan * case 1. the console was removed but there is at least one
716*3401Snarayan * another console in the group that client can connect to.
717*3401Snarayan * case 2. there is no console in the group. Client needs to
718*3401Snarayan * be disconnected from vntsd.
719*3401Snarayan */
720*3401Snarayan if (groupp->num_cons == 0) {
721*3401Snarayan (void) mutex_unlock(&groupp->lock);
722*3401Snarayan client_fini(groupp, clientp);
723*3401Snarayan } else {
724*3401Snarayan (void) mutex_unlock(&groupp->lock);
725*3401Snarayan client_init(clientp);
726*3401Snarayan }
727*3401Snarayan return;
728*3401Snarayan
729*3401Snarayan
7301991Sheppo case VNTSD_ERR_INVALID_INPUT:
7313151Ssg70180 (void) mutex_unlock(&groupp->lock);
7321991Sheppo return;
7331991Sheppo
7341991Sheppo default:
7351991Sheppo /* fatal error */
7363151Ssg70180 (void) mutex_unlock(&groupp->lock);
7371991Sheppo vntsd_log(status, err_msg);
7381991Sheppo client_fini(groupp, clientp);
7391991Sheppo return;
7401991Sheppo }
7411991Sheppo }
7421991Sheppo
7431991Sheppo /* console thread */
7441991Sheppo void *
vntsd_console_thread(vntsd_thr_arg_t * argp)7451991Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp)
7461991Sheppo {
7471991Sheppo vntsd_group_t *groupp;
7481991Sheppo vntsd_cons_t *consp;
7491991Sheppo vntsd_client_t *clientp;
7501991Sheppo
7511991Sheppo char buf[MAXHOSTNAMELEN];
7521991Sheppo char prompt[72];
7531991Sheppo char cmd;
7541991Sheppo int rv = VNTSD_SUCCESS;
7551991Sheppo int num_cons;
7561991Sheppo
7571991Sheppo
7581991Sheppo groupp = (vntsd_group_t *)argp->handle;
7591991Sheppo clientp = (vntsd_client_t *)argp->arg;
7601991Sheppo
7611991Sheppo assert(groupp);
7621991Sheppo assert(clientp);
7631991Sheppo
764*3401Snarayan /* free argp, which was allocated in listen thread */
765*3401Snarayan free(argp);
766*3401Snarayan
7671991Sheppo /* check if group is removed */
7681991Sheppo
7691991Sheppo D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(),
7701991Sheppo groupp->tcp_port, clientp->sockfd);
7711991Sheppo
7721991Sheppo bzero(buf, MAXHOSTNAMELEN);
7731991Sheppo
7741991Sheppo /* host name */
7751991Sheppo if (gethostname(buf, MAXHOSTNAMELEN)) {
7761991Sheppo vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()");
7771991Sheppo (void) snprintf(buf, sizeof (buf), "unkown host");
7781991Sheppo }
7791991Sheppo
7801991Sheppo if (snprintf(prompt, sizeof (prompt),
7812109Slm66018 "%s-vnts-%s: h, l, c{id}, n{name}, q:",
7821991Sheppo buf, groupp->group_name) >= sizeof (prompt)) {
7831991Sheppo /* long prompt doesn't fit, use short one */
7841991Sheppo (void) snprintf(prompt, sizeof (prompt),
7852109Slm66018 "vnts: h, l, c{id}, n{name}, q:");
7861991Sheppo }
7871991Sheppo
7881991Sheppo
7891991Sheppo for (;;) {
7901991Sheppo cmd = ' ';
7911991Sheppo D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(),
7921991Sheppo groupp->tcp_port, clientp->sockfd);
7931991Sheppo
7941991Sheppo num_cons = vntsd_chk_group_total_cons(groupp);
7951991Sheppo
7961991Sheppo if ((num_cons > 1) && (clientp->cons == NULL)) {
7971991Sheppo /* console to connect to */
7981991Sheppo rv = read_cmd(clientp, prompt, &cmd);
7991991Sheppo /* check error and may exit */
8001991Sheppo console_chk_status(groupp, clientp, rv);
8013151Ssg70180
8023151Ssg70180 /* any console is removed from group? */
8033151Ssg70180 num_cons = vntsd_chk_group_total_cons(groupp);
8043151Ssg70180 if (num_cons <= 1) {
8053151Ssg70180 cmd = ' ';
8063151Ssg70180 }
8071991Sheppo }
8081991Sheppo
8091991Sheppo switch (cmd) {
8101991Sheppo
8111991Sheppo case 'l':
8121991Sheppo
8131991Sheppo /* list domain names */
8141991Sheppo rv = list_all_domains(groupp, clientp);
8151991Sheppo break;
8161991Sheppo
8171991Sheppo
8181991Sheppo case 'q':
8191991Sheppo
8201991Sheppo rv = VNTSD_STATUS_CLIENT_QUIT;
8211991Sheppo break;
8221991Sheppo
8232109Slm66018 case ' ':
8242109Slm66018
825*3401Snarayan if (num_cons == 0) {
8263151Ssg70180 /* no console in the group */
827*3401Snarayan rv = VNTSD_STATUS_NO_CONS;
8283151Ssg70180 break;
829*3401Snarayan }
8303151Ssg70180
8312109Slm66018 if (clientp->cons == NULL) {
8322109Slm66018 if (num_cons == 1) {
8332109Slm66018 /* by pass selecting console */
8342109Slm66018 consp = (vntsd_cons_t *)
8352109Slm66018 (groupp->conspq->handle);
8362109Slm66018 } else {
8372109Slm66018 continue;
8382109Slm66018 }
8392109Slm66018
8402109Slm66018 } else {
8412109Slm66018 consp = clientp->cons;
8422109Slm66018 }
8432109Slm66018
8442109Slm66018 /* connect to console */
8452109Slm66018 rv = connect_cons(consp, clientp);
8462109Slm66018
8471991Sheppo break;
8481991Sheppo
8492109Slm66018 case 'c':
8502109Slm66018 case 'n':
8511991Sheppo /* select console */
8521991Sheppo if (clientp->cons == NULL) {
8532109Slm66018 rv = select_cons(groupp, &consp, clientp, cmd);
8541991Sheppo if (rv == VNTSD_ERR_INVALID_INPUT) {
8551991Sheppo rv = display_help(clientp);
8561991Sheppo break;
8571991Sheppo }
858*3401Snarayan
859*3401Snarayan /*
860*3401Snarayan * all consoles in the group
861*3401Snarayan * may be gone before this client
862*3401Snarayan * could select one.
863*3401Snarayan */
864*3401Snarayan if (rv != VNTSD_SUCCESS)
865*3401Snarayan break;
866*3401Snarayan
8671991Sheppo } else {
8681991Sheppo consp = clientp->cons;
8691991Sheppo }
8701991Sheppo assert(consp);
8711991Sheppo
8721991Sheppo /* connect to console */
8731991Sheppo rv = connect_cons(consp, clientp);
8741991Sheppo D1(stderr, "t@%d console_thread()"
8751991Sheppo "connect_cons returns %d\n",
8761991Sheppo thr_self(), rv);
8771991Sheppo break;
8781991Sheppo
8792109Slm66018 case 'h':
8802109Slm66018 default:
8812109Slm66018 rv = display_help(clientp);
8822109Slm66018 break;
8832109Slm66018
8841991Sheppo }
8852109Slm66018
8861991Sheppo /* check error and may exit */
8871991Sheppo console_chk_status(groupp, clientp, rv);
8881991Sheppo }
8891991Sheppo
8901991Sheppo /*NOTREACHED*/
8911991Sheppo return (NULL);
8921991Sheppo }
893