xref: /titanic_51/usr/src/cmd/vntsd/console.c (revision 1ae0874509b6811fdde1dfd46f0d93fd09867a3f)
1*1ae08745Sheppo /*
2*1ae08745Sheppo  * CDDL HEADER START
3*1ae08745Sheppo  *
4*1ae08745Sheppo  * The contents of this file are subject to the terms of the
5*1ae08745Sheppo  * Common Development and Distribution License (the "License").
6*1ae08745Sheppo  * You may not use this file except in compliance with the License.
7*1ae08745Sheppo  *
8*1ae08745Sheppo  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*1ae08745Sheppo  * or http://www.opensolaris.org/os/licensing.
10*1ae08745Sheppo  * See the License for the specific language governing permissions
11*1ae08745Sheppo  * and limitations under the License.
12*1ae08745Sheppo  *
13*1ae08745Sheppo  * When distributing Covered Code, include this CDDL HEADER in each
14*1ae08745Sheppo  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*1ae08745Sheppo  * If applicable, add the following below this CDDL HEADER, with the
16*1ae08745Sheppo  * fields enclosed by brackets "[]" replaced with your own identifying
17*1ae08745Sheppo  * information: Portions Copyright [yyyy] [name of copyright owner]
18*1ae08745Sheppo  *
19*1ae08745Sheppo  * CDDL HEADER END
20*1ae08745Sheppo  */
21*1ae08745Sheppo /*
22*1ae08745Sheppo  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23*1ae08745Sheppo  * Use is subject to license terms.
24*1ae08745Sheppo  */
25*1ae08745Sheppo #pragma ident	"%Z%%M%	%I%	%E% SMI"
26*1ae08745Sheppo 
27*1ae08745Sheppo /*
28*1ae08745Sheppo  * Listen thread creates a console thread whenever there is a tcp client
29*1ae08745Sheppo  * made a conection to its port. In the console thread, if there are
30*1ae08745Sheppo  * multiple consoles in the group, client will be asked for a console selection.
31*1ae08745Sheppo  * a write thread for a console is created when first client connects to a
32*1ae08745Sheppo  * selected console and console thread becomes read thread for the client.
33*1ae08745Sheppo  */
34*1ae08745Sheppo 
35*1ae08745Sheppo #include <stdio.h>
36*1ae08745Sheppo #include <stdlib.h>
37*1ae08745Sheppo #include <string.h>
38*1ae08745Sheppo #include <unistd.h>
39*1ae08745Sheppo #include <sys/types.h>
40*1ae08745Sheppo #include <sys/socket.h>
41*1ae08745Sheppo #include <netinet/in.h>
42*1ae08745Sheppo #include <thread.h>
43*1ae08745Sheppo #include <synch.h>
44*1ae08745Sheppo #include <signal.h>
45*1ae08745Sheppo #include <assert.h>
46*1ae08745Sheppo #include <ctype.h>
47*1ae08745Sheppo #include <syslog.h>
48*1ae08745Sheppo #include <libintl.h>
49*1ae08745Sheppo #include <netdb.h>
50*1ae08745Sheppo #include "vntsd.h"
51*1ae08745Sheppo #include "chars.h"
52*1ae08745Sheppo 
53*1ae08745Sheppo /*  display domain names in the group */
54*1ae08745Sheppo static boolean_t
55*1ae08745Sheppo display_domain_name(vntsd_cons_t *consp,  int  *fd)
56*1ae08745Sheppo {
57*1ae08745Sheppo 	char	buf[VNTSD_LINE_LEN];
58*1ae08745Sheppo 	char	*status;
59*1ae08745Sheppo 
60*1ae08745Sheppo 
61*1ae08745Sheppo 	if (consp->clientpq != NULL) {
62*1ae08745Sheppo 		status = gettext("connected");
63*1ae08745Sheppo 	} else if (consp->status & VNTSD_CONS_DELETED) {
64*1ae08745Sheppo 		status = gettext("removing...");
65*1ae08745Sheppo 	} else {
66*1ae08745Sheppo 		status = gettext("online");
67*1ae08745Sheppo 	}
68*1ae08745Sheppo 
69*1ae08745Sheppo 	(void) snprintf(buf, sizeof (buf), "%-20d%-30s%-25s%s",
70*1ae08745Sheppo 	    consp->cons_no, consp->domain_name, status, vntsd_eol);
71*1ae08745Sheppo 
72*1ae08745Sheppo 	return (vntsd_write_fd(*fd, buf, strlen(buf)) != VNTSD_SUCCESS);
73*1ae08745Sheppo }
74*1ae08745Sheppo 
75*1ae08745Sheppo /* output connected message to tcp client */
76*1ae08745Sheppo static int
77*1ae08745Sheppo write_connect_msg(vntsd_client_t *clientp, char *group_name,
78*1ae08745Sheppo     char *domain_name)
79*1ae08745Sheppo {
80*1ae08745Sheppo 
81*1ae08745Sheppo 	int	rv = VNTSD_SUCCESS;
82*1ae08745Sheppo 	char	buf[VNTSD_LINE_LEN];
83*1ae08745Sheppo 
84*1ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN)) !=
85*1ae08745Sheppo 	    VNTSD_SUCCESS) {
86*1ae08745Sheppo 		return (rv);
87*1ae08745Sheppo 	}
88*1ae08745Sheppo 
89*1ae08745Sheppo 	(void) snprintf(buf, sizeof (buf),
90*1ae08745Sheppo 	    gettext("Connecting to console \"%s\" in group \"%s\" ...."),
91*1ae08745Sheppo 	    domain_name, group_name);
92*1ae08745Sheppo 
93*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, buf)) != VNTSD_SUCCESS) {
94*1ae08745Sheppo 		return (rv);
95*1ae08745Sheppo 	}
96*1ae08745Sheppo 
97*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp,
98*1ae08745Sheppo 			    gettext("Press ~? for control options .."))) !=
99*1ae08745Sheppo 	    VNTSD_SUCCESS) {
100*1ae08745Sheppo 		return (rv);
101*1ae08745Sheppo 	}
102*1ae08745Sheppo 
103*1ae08745Sheppo 	return (VNTSD_SUCCESS);
104*1ae08745Sheppo }
105*1ae08745Sheppo 
106*1ae08745Sheppo static int
107*1ae08745Sheppo create_write_thread(vntsd_cons_t *consp)
108*1ae08745Sheppo {
109*1ae08745Sheppo 
110*1ae08745Sheppo 	assert(consp);
111*1ae08745Sheppo 
112*1ae08745Sheppo 	/* create write thread for the console */
113*1ae08745Sheppo 	(void) mutex_lock(&consp->lock);
114*1ae08745Sheppo 	if (thr_create(NULL, 0, (thr_func_t)vntsd_write_thread,
115*1ae08745Sheppo 		    (void *)consp, NULL, &consp->wr_tid)) {
116*1ae08745Sheppo 
117*1ae08745Sheppo 		DERR(stderr, "t@%d create_rd_wr_thread@%d: "
118*1ae08745Sheppo 		    "create write thread failed\n",
119*1ae08745Sheppo 		    thr_self(), consp->cons_no);
120*1ae08745Sheppo 		(void) close(consp->vcc_fd);
121*1ae08745Sheppo 		consp->vcc_fd = -1;
122*1ae08745Sheppo 		(void) mutex_unlock(&consp->lock);
123*1ae08745Sheppo 
124*1ae08745Sheppo 		return (VNTSD_ERR_CREATE_WR_THR);
125*1ae08745Sheppo 	}
126*1ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
127*1ae08745Sheppo 	return (VNTSD_SUCCESS);
128*1ae08745Sheppo }
129*1ae08745Sheppo 
130*1ae08745Sheppo /* Display all domain consoles in a group. */
131*1ae08745Sheppo static int
132*1ae08745Sheppo list_all_domains(vntsd_group_t *groupp, vntsd_client_t *clientp)
133*1ae08745Sheppo {
134*1ae08745Sheppo 	char	    vntsd_line[VNTSD_LINE_LEN];
135*1ae08745Sheppo 	int	    rv = VNTSD_SUCCESS;
136*1ae08745Sheppo 
137*1ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
138*1ae08745Sheppo 	    != VNTSD_SUCCESS) {
139*1ae08745Sheppo 		return (rv);
140*1ae08745Sheppo 	}
141*1ae08745Sheppo 
142*1ae08745Sheppo 	/*
143*1ae08745Sheppo 	 * TRANSLATION_NOTE
144*1ae08745Sheppo 	 * The following three strings of the form "DOMAIN .." are table
145*1ae08745Sheppo 	 * headers and should be all uppercase.
146*1ae08745Sheppo 	 */
147*1ae08745Sheppo 	(void) snprintf(vntsd_line, sizeof (vntsd_line),
148*1ae08745Sheppo 	    "%-20s%-30s%-25s",
149*1ae08745Sheppo 	    gettext("DOMAIN ID"), gettext("DOMAIN NAME"),
150*1ae08745Sheppo 	    gettext("DOMAIN STATE"));
151*1ae08745Sheppo 
152*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, vntsd_line)) != VNTSD_SUCCESS) {
153*1ae08745Sheppo 		return (rv);
154*1ae08745Sheppo 	}
155*1ae08745Sheppo 
156*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
157*1ae08745Sheppo 
158*1ae08745Sheppo 	if (vntsd_que_find(groupp->conspq, (compare_func_t)display_domain_name,
159*1ae08745Sheppo 		    &(clientp->sockfd)) != NULL) {
160*1ae08745Sheppo 		rv = VNTSD_ERR_WRITE_CLIENT;
161*1ae08745Sheppo 	}
162*1ae08745Sheppo 
163*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
164*1ae08745Sheppo 
165*1ae08745Sheppo 	return (rv);
166*1ae08745Sheppo }
167*1ae08745Sheppo 
168*1ae08745Sheppo /* display help */
169*1ae08745Sheppo static int
170*1ae08745Sheppo display_help(vntsd_client_t *clientp)
171*1ae08745Sheppo {
172*1ae08745Sheppo 	int	rv = VNTSD_SUCCESS;
173*1ae08745Sheppo 	char	*bufp;
174*1ae08745Sheppo 
175*1ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
176*1ae08745Sheppo 		!= VNTSD_SUCCESS) {
177*1ae08745Sheppo 		return (rv);
178*1ae08745Sheppo 	}
179*1ae08745Sheppo 
180*1ae08745Sheppo 	/*
181*1ae08745Sheppo 	 * TRANSLATION_NOTE
182*1ae08745Sheppo 	 * The following three strings of the form ". -- ..." are help
183*1ae08745Sheppo 	 * messages for single character commands. Do not translate the
184*1ae08745Sheppo 	 * character before the --.
185*1ae08745Sheppo 	 */
186*1ae08745Sheppo 	bufp = gettext("h -- this help)");
187*1ae08745Sheppo 
188*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
189*1ae08745Sheppo 		return (rv);
190*1ae08745Sheppo 	}
191*1ae08745Sheppo 
192*1ae08745Sheppo 	bufp = gettext("l -- list of consoles");
193*1ae08745Sheppo 
194*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
195*1ae08745Sheppo 		return (rv);
196*1ae08745Sheppo 	}
197*1ae08745Sheppo 
198*1ae08745Sheppo 	bufp = gettext("q -- quit");
199*1ae08745Sheppo 
200*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
201*1ae08745Sheppo 		return (rv);
202*1ae08745Sheppo 	}
203*1ae08745Sheppo 
204*1ae08745Sheppo 	/*
205*1ae08745Sheppo 	 * TRANSLATION_NOTE
206*1ae08745Sheppo 	 * In the following string, "id" is a short mnemonic for
207*1ae08745Sheppo 	 * "identifier" and both occurrences should be translated.
208*1ae08745Sheppo 	 */
209*1ae08745Sheppo 
210*1ae08745Sheppo 	bufp = gettext("[c[c ]]{id} -- connect to console of domain {id}");
211*1ae08745Sheppo 
212*1ae08745Sheppo 	if ((rv = vntsd_write_line(clientp, bufp)) != VNTSD_SUCCESS) {
213*1ae08745Sheppo 		return (rv);
214*1ae08745Sheppo 	}
215*1ae08745Sheppo 
216*1ae08745Sheppo 	return (VNTSD_SUCCESS);
217*1ae08745Sheppo }
218*1ae08745Sheppo 
219*1ae08745Sheppo /* select a console to connect */
220*1ae08745Sheppo static int
221*1ae08745Sheppo select_cons(vntsd_group_t *groupp, int num_cons, vntsd_cons_t **consp,
222*1ae08745Sheppo     vntsd_client_t *clientp, char c)
223*1ae08745Sheppo {
224*1ae08745Sheppo 	int	    cons_no = -2;
225*1ae08745Sheppo 	int	    n;
226*1ae08745Sheppo 	int	    i;
227*1ae08745Sheppo 	char	    buf[VNTSD_LINE_LEN];
228*1ae08745Sheppo 	int	    rv;
229*1ae08745Sheppo 
230*1ae08745Sheppo 
231*1ae08745Sheppo 
232*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
233*1ae08745Sheppo 	if (groupp->num_cons == 0) {
234*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
235*1ae08745Sheppo 		/* no console in this group */
236*1ae08745Sheppo 		return (VNTSD_STATUS_NO_CONS);
237*1ae08745Sheppo 	}
238*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
239*1ae08745Sheppo 
240*1ae08745Sheppo 	if (num_cons == 1) {
241*1ae08745Sheppo 		/* by pass selecting console */
242*1ae08745Sheppo 		*consp = (vntsd_cons_t *)(groupp->conspq->handle);
243*1ae08745Sheppo 		return (VNTSD_SUCCESS);
244*1ae08745Sheppo 	}
245*1ae08745Sheppo 
246*1ae08745Sheppo 
247*1ae08745Sheppo 	if (isdigit(c)) {
248*1ae08745Sheppo 		/* {id} input */
249*1ae08745Sheppo 		cons_no = c - '0';
250*1ae08745Sheppo 	} else if (c == 'c') {
251*1ae08745Sheppo 		/* c{id} or c {id} input */
252*1ae08745Sheppo 		cons_no = -1;
253*1ae08745Sheppo 	} else if (!isspace(c)) {
254*1ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
255*1ae08745Sheppo 	}
256*1ae08745Sheppo 
257*1ae08745Sheppo 	/* get client selections */
258*1ae08745Sheppo 	n = VNTSD_LINE_LEN;
259*1ae08745Sheppo 
260*1ae08745Sheppo 	if ((rv = vntsd_read_line(clientp, buf, &n)) != VNTSD_SUCCESS) {
261*1ae08745Sheppo 		return (rv);
262*1ae08745Sheppo 	}
263*1ae08745Sheppo 
264*1ae08745Sheppo 	/* parse command */
265*1ae08745Sheppo 	for (i = 0; i < n; i++) {
266*1ae08745Sheppo 		if (cons_no == -1) {
267*1ae08745Sheppo 			/* c{id} */
268*1ae08745Sheppo 			cons_no = atoi(buf + i);
269*1ae08745Sheppo 			break;
270*1ae08745Sheppo 		}
271*1ae08745Sheppo 
272*1ae08745Sheppo 		if (isspace(buf[i]) && cons_no == -2) {
273*1ae08745Sheppo 			/* skip space */
274*1ae08745Sheppo 			continue;
275*1ae08745Sheppo 		}
276*1ae08745Sheppo 
277*1ae08745Sheppo 		if (buf[i] == 'c') {
278*1ae08745Sheppo 			/* c{id} or c {id} */
279*1ae08745Sheppo 			cons_no = -1;
280*1ae08745Sheppo 		} else if (buf[i] == CR) {
281*1ae08745Sheppo 			break;
282*1ae08745Sheppo 		} else {
283*1ae08745Sheppo 			return (VNTSD_ERR_INVALID_INPUT);
284*1ae08745Sheppo 		}
285*1ae08745Sheppo 	}
286*1ae08745Sheppo 
287*1ae08745Sheppo 	if (cons_no < 0) {
288*1ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
289*1ae08745Sheppo 	}
290*1ae08745Sheppo 
291*1ae08745Sheppo 	/* get selected console */
292*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
293*1ae08745Sheppo 
294*1ae08745Sheppo 	*consp = (vntsd_cons_t *)vntsd_que_find(groupp->conspq,
295*1ae08745Sheppo 		    (compare_func_t)vntsd_cons_by_consno, &cons_no);
296*1ae08745Sheppo 
297*1ae08745Sheppo 	if (*consp == NULL) {
298*1ae08745Sheppo 		/* during console selection, the console has been  deleted */
299*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
300*1ae08745Sheppo 
301*1ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
302*1ae08745Sheppo 	}
303*1ae08745Sheppo 	if ((*consp)->status & VNTSD_CONS_DELETED) {
304*1ae08745Sheppo 		return (VNTSD_ERR_INVALID_INPUT);
305*1ae08745Sheppo 	}
306*1ae08745Sheppo 
307*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
308*1ae08745Sheppo 
309*1ae08745Sheppo 	return (VNTSD_SUCCESS);
310*1ae08745Sheppo }
311*1ae08745Sheppo 
312*1ae08745Sheppo /* compare if there is a match console in the gorup */
313*1ae08745Sheppo static boolean_t
314*1ae08745Sheppo find_cons_in_group(vntsd_cons_t *consp_in_group, vntsd_cons_t *consp)
315*1ae08745Sheppo {
316*1ae08745Sheppo 	if (consp_in_group == consp) {
317*1ae08745Sheppo 		return (B_TRUE);
318*1ae08745Sheppo 	} else {
319*1ae08745Sheppo 		return (B_FALSE);
320*1ae08745Sheppo 	}
321*1ae08745Sheppo }
322*1ae08745Sheppo 
323*1ae08745Sheppo /* connect a client to a console */
324*1ae08745Sheppo static int
325*1ae08745Sheppo connect_cons(vntsd_cons_t *consp, vntsd_client_t *clientp)
326*1ae08745Sheppo {
327*1ae08745Sheppo 	int	rv, rv1;
328*1ae08745Sheppo 	vntsd_group_t *groupp;
329*1ae08745Sheppo 
330*1ae08745Sheppo 	assert(consp);
331*1ae08745Sheppo 	groupp = consp->group;
332*1ae08745Sheppo 	assert(groupp);
333*1ae08745Sheppo 	assert(clientp);
334*1ae08745Sheppo 
335*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
336*1ae08745Sheppo 
337*1ae08745Sheppo 	/* check if console is valid */
338*1ae08745Sheppo 	consp = vntsd_que_find(groupp->conspq,
339*1ae08745Sheppo 	    (compare_func_t)find_cons_in_group, consp);
340*1ae08745Sheppo 
341*1ae08745Sheppo 	if (consp == NULL) {
342*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
343*1ae08745Sheppo 		return (VNTSD_STATUS_NO_CONS);
344*1ae08745Sheppo 	}
345*1ae08745Sheppo 	if (consp->status & VNTSD_CONS_DELETED) {
346*1ae08745Sheppo 		(void) mutex_unlock(&groupp->lock);
347*1ae08745Sheppo 		return (VNTSD_STATUS_NO_CONS);
348*1ae08745Sheppo 	}
349*1ae08745Sheppo 
350*1ae08745Sheppo 	(void) mutex_lock(&consp->lock);
351*1ae08745Sheppo 	(void) mutex_lock(&clientp->lock);
352*1ae08745Sheppo 
353*1ae08745Sheppo 
354*1ae08745Sheppo 	clientp->cons = consp;
355*1ae08745Sheppo 
356*1ae08745Sheppo 	/* enable daemon cmd */
357*1ae08745Sheppo 	clientp->status &= ~VNTSD_CLIENT_DISABLE_DAEMON_CMD;
358*1ae08745Sheppo 
359*1ae08745Sheppo 	if (consp->clientpq == NULL) {
360*1ae08745Sheppo 		/* first connect to console - a writer */
361*1ae08745Sheppo 		assert(consp->vcc_fd == -1);
362*1ae08745Sheppo 		/* open vcc */
363*1ae08745Sheppo 		consp->vcc_fd = vntsd_open_vcc(consp->dev_name, consp->cons_no);
364*1ae08745Sheppo 		if (consp->vcc_fd < 0) {
365*1ae08745Sheppo 			(void) mutex_unlock(&clientp->lock);
366*1ae08745Sheppo 			(void) mutex_unlock(&consp->lock);
367*1ae08745Sheppo 			(void) mutex_unlock(&groupp->lock);
368*1ae08745Sheppo 			assert(consp->group);
369*1ae08745Sheppo 			return (vntsd_vcc_err(consp));
370*1ae08745Sheppo 		}
371*1ae08745Sheppo 	}
372*1ae08745Sheppo 
373*1ae08745Sheppo 	(void) mutex_unlock(&clientp->lock);
374*1ae08745Sheppo 
375*1ae08745Sheppo 	/*
376*1ae08745Sheppo 	 * move the client from group's no console selected queue
377*1ae08745Sheppo 	 * to cons queue
378*1ae08745Sheppo 	 */
379*1ae08745Sheppo 
380*1ae08745Sheppo 	rv = vntsd_que_rm(&groupp->no_cons_clientpq, clientp);
381*1ae08745Sheppo 	assert(rv == VNTSD_SUCCESS);
382*1ae08745Sheppo 
383*1ae08745Sheppo 	rv = vntsd_que_append(&consp->clientpq, clientp);
384*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
385*1ae08745Sheppo 
386*1ae08745Sheppo 	if (rv != VNTSD_SUCCESS) {
387*1ae08745Sheppo 		if (consp->clientpq->handle == clientp) {
388*1ae08745Sheppo 			/* writer */
389*1ae08745Sheppo 			(void) close(consp->vcc_fd);
390*1ae08745Sheppo 			consp->vcc_fd = -1;
391*1ae08745Sheppo 		}
392*1ae08745Sheppo 
393*1ae08745Sheppo 		(void) mutex_unlock(&consp->lock);
394*1ae08745Sheppo 		return (rv);
395*1ae08745Sheppo 	}
396*1ae08745Sheppo 
397*1ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
398*1ae08745Sheppo 
399*1ae08745Sheppo 	if (consp->clientpq->handle == clientp) {
400*1ae08745Sheppo 		/* create a write thread */
401*1ae08745Sheppo 		rv = create_write_thread(consp);
402*1ae08745Sheppo 		if (rv != VNTSD_SUCCESS) {
403*1ae08745Sheppo 			return (rv);
404*1ae08745Sheppo 		}
405*1ae08745Sheppo 	}
406*1ae08745Sheppo 
407*1ae08745Sheppo 	/* write connecting message */
408*1ae08745Sheppo 	if ((rv = write_connect_msg(clientp, consp->group->group_name,
409*1ae08745Sheppo 	    consp->domain_name)) != VNTSD_SUCCESS) {
410*1ae08745Sheppo 			return (rv);
411*1ae08745Sheppo 	}
412*1ae08745Sheppo 
413*1ae08745Sheppo 	/* process input from client */
414*1ae08745Sheppo 	rv = vntsd_read(clientp);
415*1ae08745Sheppo 
416*1ae08745Sheppo 	/* client disconnected from the console */
417*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
418*1ae08745Sheppo 
419*1ae08745Sheppo 	/* remove client from console queue */
420*1ae08745Sheppo 	(void) mutex_lock(&consp->lock);
421*1ae08745Sheppo 	rv1 = vntsd_que_rm(&consp->clientpq, clientp);
422*1ae08745Sheppo 	assert(rv1 == VNTSD_SUCCESS);
423*1ae08745Sheppo 
424*1ae08745Sheppo 	/* append client to group's no console selected  queue */
425*1ae08745Sheppo 	rv1 = vntsd_que_append(&groupp->no_cons_clientpq, clientp);
426*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
427*1ae08745Sheppo 
428*1ae08745Sheppo 	if (consp->clientpq == NULL) {
429*1ae08745Sheppo 		/* clean up console since there is no client connected to it */
430*1ae08745Sheppo 		assert(consp->vcc_fd != -1);
431*1ae08745Sheppo 
432*1ae08745Sheppo 		/* close vcc port */
433*1ae08745Sheppo 		(void) close(consp->vcc_fd);
434*1ae08745Sheppo 		consp->vcc_fd = -1;
435*1ae08745Sheppo 
436*1ae08745Sheppo 		/* force write thread to exit */
437*1ae08745Sheppo 		assert(consp->wr_tid != (thread_t)-1);
438*1ae08745Sheppo 		(void) thr_kill(consp->wr_tid, SIGUSR1);
439*1ae08745Sheppo 		(void) mutex_unlock(&consp->lock);
440*1ae08745Sheppo 		(void) thr_join(consp->wr_tid, NULL, NULL);
441*1ae08745Sheppo 		(void) mutex_lock(&consp->lock);
442*1ae08745Sheppo 	}
443*1ae08745Sheppo 
444*1ae08745Sheppo 	if (consp->status & VNTSD_CONS_SIG_WAIT) {
445*1ae08745Sheppo 		/* console is waiting for client to disconnect */
446*1ae08745Sheppo 		(void) cond_signal(&consp->cvp);
447*1ae08745Sheppo 	}
448*1ae08745Sheppo 
449*1ae08745Sheppo 	(void) mutex_unlock(&consp->lock);
450*1ae08745Sheppo 
451*1ae08745Sheppo 	return (rv1 == VNTSD_SUCCESS ? rv : rv1);
452*1ae08745Sheppo 
453*1ae08745Sheppo }
454*1ae08745Sheppo 
455*1ae08745Sheppo /* read command line input */
456*1ae08745Sheppo static int
457*1ae08745Sheppo read_cmd(vntsd_client_t *clientp, char *prompt, char *cmd)
458*1ae08745Sheppo {
459*1ae08745Sheppo 	int		rv;
460*1ae08745Sheppo 
461*1ae08745Sheppo 	/* disable daemon special command */
462*1ae08745Sheppo 	(void) mutex_lock(&clientp->lock);
463*1ae08745Sheppo 	clientp->status |= VNTSD_CLIENT_DISABLE_DAEMON_CMD;
464*1ae08745Sheppo 	(void) mutex_unlock(&clientp->lock);
465*1ae08745Sheppo 
466*1ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN))
467*1ae08745Sheppo 	    != VNTSD_SUCCESS) {
468*1ae08745Sheppo 		return (rv);
469*1ae08745Sheppo 	}
470*1ae08745Sheppo 
471*1ae08745Sheppo 	if ((rv = vntsd_write_client(clientp, prompt, strlen(prompt)))
472*1ae08745Sheppo 		!= VNTSD_SUCCESS) {
473*1ae08745Sheppo 		return (rv);
474*1ae08745Sheppo 	}
475*1ae08745Sheppo 
476*1ae08745Sheppo 	if ((rv = vntsd_read_data(clientp, cmd)) != VNTSD_SUCCESS) {
477*1ae08745Sheppo 		return (rv);
478*1ae08745Sheppo 	}
479*1ae08745Sheppo 	if (*cmd == BS) {
480*1ae08745Sheppo 		return (VNTSD_SUCCESS);
481*1ae08745Sheppo 	}
482*1ae08745Sheppo 
483*1ae08745Sheppo 	rv = vntsd_write_client(clientp, cmd, 1);
484*1ae08745Sheppo 
485*1ae08745Sheppo 	*cmd = tolower(*cmd);
486*1ae08745Sheppo 
487*1ae08745Sheppo 	return (rv);
488*1ae08745Sheppo }
489*1ae08745Sheppo 
490*1ae08745Sheppo /* reset client for selecting a console in the group */
491*1ae08745Sheppo static void
492*1ae08745Sheppo client_init(vntsd_client_t *clientp)
493*1ae08745Sheppo {
494*1ae08745Sheppo 	(void) mutex_lock(&clientp->lock);
495*1ae08745Sheppo 	clientp->cons = NULL;
496*1ae08745Sheppo 	clientp->status = 0;
497*1ae08745Sheppo 	(void) mutex_unlock(&clientp->lock);
498*1ae08745Sheppo }
499*1ae08745Sheppo 
500*1ae08745Sheppo /* clean up client and exit the thread */
501*1ae08745Sheppo static void
502*1ae08745Sheppo client_fini(vntsd_group_t *groupp, vntsd_client_t *clientp)
503*1ae08745Sheppo {
504*1ae08745Sheppo 
505*1ae08745Sheppo 	assert(groupp);
506*1ae08745Sheppo 	assert(clientp);
507*1ae08745Sheppo 
508*1ae08745Sheppo 	/* disconnct client from tcp port */
509*1ae08745Sheppo 	assert(clientp->sockfd != -1);
510*1ae08745Sheppo 	(void) close(clientp->sockfd);
511*1ae08745Sheppo 
512*1ae08745Sheppo 	(void) mutex_lock(&groupp->lock);
513*1ae08745Sheppo 	(void) vntsd_que_rm(&groupp->no_cons_clientpq, clientp);
514*1ae08745Sheppo 
515*1ae08745Sheppo 	if ((groupp->no_cons_clientpq == NULL) &&
516*1ae08745Sheppo 	    (groupp->status & VNTSD_GROUP_SIG_WAIT)) {
517*1ae08745Sheppo 		/* group is waiting to be deleted */
518*1ae08745Sheppo 		groupp->status &= ~VNTSD_GROUP_SIG_WAIT;
519*1ae08745Sheppo 		(void) cond_signal(&groupp->cvp);
520*1ae08745Sheppo 	}
521*1ae08745Sheppo 	(void) mutex_unlock(&groupp->lock);
522*1ae08745Sheppo 
523*1ae08745Sheppo 	(void) mutex_destroy(&clientp->lock);
524*1ae08745Sheppo 	free(clientp);
525*1ae08745Sheppo 
526*1ae08745Sheppo 	thr_exit(0);
527*1ae08745Sheppo }
528*1ae08745Sheppo 
529*1ae08745Sheppo /*  check client's status. exit if client quits or fatal errors */
530*1ae08745Sheppo static void
531*1ae08745Sheppo console_chk_status(vntsd_group_t *groupp, vntsd_client_t *clientp, int status)
532*1ae08745Sheppo {
533*1ae08745Sheppo 	char    err_msg[VNTSD_LINE_LEN];
534*1ae08745Sheppo 
535*1ae08745Sheppo 	D1(stderr, "t@%d console_chk_status() status=%d "
536*1ae08745Sheppo 	    "client status=%x num consoles=%d \n",
537*1ae08745Sheppo 	    thr_self(), status, clientp->status, groupp->num_cons);
538*1ae08745Sheppo 
539*1ae08745Sheppo 	(void) snprintf(err_msg, VNTSD_LINE_LEN, "console_chk_status client%d"
540*1ae08745Sheppo 	    " num_cos=%d", clientp->sockfd, groupp->num_cons);
541*1ae08745Sheppo 
542*1ae08745Sheppo 	if (groupp->num_cons == 0) {
543*1ae08745Sheppo 		/* no more console in the group */
544*1ae08745Sheppo 		client_fini(groupp, clientp);
545*1ae08745Sheppo 	}
546*1ae08745Sheppo 
547*1ae08745Sheppo 	if (status == VNTSD_STATUS_INTR) {
548*1ae08745Sheppo 		/* reason for signal? */
549*1ae08745Sheppo 		status = vntsd_cons_chk_intr(clientp);
550*1ae08745Sheppo 	}
551*1ae08745Sheppo 
552*1ae08745Sheppo 	switch (status) {
553*1ae08745Sheppo 
554*1ae08745Sheppo 	case VNTSD_STATUS_CLIENT_QUIT:
555*1ae08745Sheppo 		client_fini(groupp, clientp);
556*1ae08745Sheppo 		return;
557*1ae08745Sheppo 
558*1ae08745Sheppo 	case VNTSD_STATUS_RESELECT_CONS:
559*1ae08745Sheppo 		assert(clientp->cons);
560*1ae08745Sheppo 		if ((groupp->num_cons == 1) &&
561*1ae08745Sheppo 		    (groupp->conspq->handle == clientp->cons)) {
562*1ae08745Sheppo 			/* no other selection available */
563*1ae08745Sheppo 			client_fini(groupp, clientp);
564*1ae08745Sheppo 		} else {
565*1ae08745Sheppo 			client_init(clientp);
566*1ae08745Sheppo 		}
567*1ae08745Sheppo 		return;
568*1ae08745Sheppo 
569*1ae08745Sheppo 	case VNTSD_STATUS_VCC_IO_ERR:
570*1ae08745Sheppo 		if ((clientp->status & VNTSD_CLIENT_CONS_DELETED) == 0) {
571*1ae08745Sheppo 			/* check if console was deleted  */
572*1ae08745Sheppo 			status = vntsd_vcc_err(clientp->cons);
573*1ae08745Sheppo 		}
574*1ae08745Sheppo 
575*1ae08745Sheppo 		if (status != VNTSD_STATUS_CONTINUE) {
576*1ae08745Sheppo 			/* console was deleted */
577*1ae08745Sheppo 			if (groupp->num_cons == 1) {
578*1ae08745Sheppo 				client_fini(groupp, clientp);
579*1ae08745Sheppo 			}
580*1ae08745Sheppo 		}
581*1ae08745Sheppo 
582*1ae08745Sheppo 		/* console is ok */
583*1ae08745Sheppo 		client_init(clientp);
584*1ae08745Sheppo 		return;
585*1ae08745Sheppo 
586*1ae08745Sheppo 	case VNTSD_STATUS_MOV_CONS_FORWARD:
587*1ae08745Sheppo 	case VNTSD_STATUS_MOV_CONS_BACKWARD:
588*1ae08745Sheppo 		if (groupp->num_cons == 1) {
589*1ae08745Sheppo 			/* same console */
590*1ae08745Sheppo 			return;
591*1ae08745Sheppo 		}
592*1ae08745Sheppo 
593*1ae08745Sheppo 		/* get selected console */
594*1ae08745Sheppo 		(void) mutex_lock(&(clientp->cons->group->lock));
595*1ae08745Sheppo 		clientp->cons = vntsd_que_pos(clientp->cons->group->conspq,
596*1ae08745Sheppo 		    clientp->cons,
597*1ae08745Sheppo 		    (status == VNTSD_STATUS_MOV_CONS_FORWARD)?(1):(-1));
598*1ae08745Sheppo 		(void) mutex_unlock(&(clientp->cons->group->lock));
599*1ae08745Sheppo 		return;
600*1ae08745Sheppo 
601*1ae08745Sheppo 	case VNTSD_SUCCESS:
602*1ae08745Sheppo 	case VNTSD_STATUS_CONTINUE:
603*1ae08745Sheppo 	case VNTSD_STATUS_NO_CONS:
604*1ae08745Sheppo 		client_init(clientp);
605*1ae08745Sheppo 		return;
606*1ae08745Sheppo 
607*1ae08745Sheppo 	case VNTSD_ERR_INVALID_INPUT:
608*1ae08745Sheppo 		return;
609*1ae08745Sheppo 
610*1ae08745Sheppo 	default:
611*1ae08745Sheppo 		/* fatal error */
612*1ae08745Sheppo 		vntsd_log(status, err_msg);
613*1ae08745Sheppo 		client_fini(groupp, clientp);
614*1ae08745Sheppo 		return;
615*1ae08745Sheppo 	}
616*1ae08745Sheppo }
617*1ae08745Sheppo 
618*1ae08745Sheppo /* console thread */
619*1ae08745Sheppo void *
620*1ae08745Sheppo vntsd_console_thread(vntsd_thr_arg_t *argp)
621*1ae08745Sheppo {
622*1ae08745Sheppo 	vntsd_group_t	    *groupp;
623*1ae08745Sheppo 	vntsd_cons_t	    *consp;
624*1ae08745Sheppo 	vntsd_client_t	    *clientp;
625*1ae08745Sheppo 
626*1ae08745Sheppo 	char		    buf[MAXHOSTNAMELEN];
627*1ae08745Sheppo 	char		    prompt[72];
628*1ae08745Sheppo 	char		    cmd;
629*1ae08745Sheppo 	int		    rv = VNTSD_SUCCESS;
630*1ae08745Sheppo 	int		    num_cons;
631*1ae08745Sheppo 
632*1ae08745Sheppo 
633*1ae08745Sheppo 	groupp = (vntsd_group_t *)argp->handle;
634*1ae08745Sheppo 	clientp = (vntsd_client_t *)argp->arg;
635*1ae08745Sheppo 
636*1ae08745Sheppo 	assert(groupp);
637*1ae08745Sheppo 	assert(clientp);
638*1ae08745Sheppo 
639*1ae08745Sheppo 	/* check if group is removed */
640*1ae08745Sheppo 
641*1ae08745Sheppo 	D1(stderr, "t@%d get_client_sel@%lld:client@%d\n", thr_self(),
642*1ae08745Sheppo 	    groupp->tcp_port, clientp->sockfd);
643*1ae08745Sheppo 
644*1ae08745Sheppo 	bzero(buf, MAXHOSTNAMELEN);
645*1ae08745Sheppo 
646*1ae08745Sheppo 	/* host name */
647*1ae08745Sheppo 	if (gethostname(buf, MAXHOSTNAMELEN)) {
648*1ae08745Sheppo 		vntsd_log(VNTSD_STATUS_NO_HOST_NAME, "vntsd_console_thread()");
649*1ae08745Sheppo 		(void) snprintf(buf, sizeof (buf), "unkown host");
650*1ae08745Sheppo 	}
651*1ae08745Sheppo 
652*1ae08745Sheppo 	if (snprintf(prompt, sizeof (prompt),
653*1ae08745Sheppo 		    "%s-vnts-%s: h,l,{id},c{id},c {id},q:",
654*1ae08745Sheppo 	    buf, groupp->group_name) >= sizeof (prompt)) {
655*1ae08745Sheppo 		/* long prompt doesn't fit, use short one */
656*1ae08745Sheppo 		(void) snprintf(prompt, sizeof (prompt),
657*1ae08745Sheppo 				"vnts: h,l,{id},c{id},c {id}, q:");
658*1ae08745Sheppo 	}
659*1ae08745Sheppo 
660*1ae08745Sheppo 
661*1ae08745Sheppo 	for (;;) {
662*1ae08745Sheppo 		cmd = ' ';
663*1ae08745Sheppo 		D1(stderr, "t@%d console_thread()@%lld:client@%d\n", thr_self(),
664*1ae08745Sheppo 		    groupp->tcp_port, clientp->sockfd);
665*1ae08745Sheppo 
666*1ae08745Sheppo 		num_cons = vntsd_chk_group_total_cons(groupp);
667*1ae08745Sheppo 
668*1ae08745Sheppo 		if ((num_cons > 1) && (clientp->cons == NULL)) {
669*1ae08745Sheppo 			/*  console to connect to */
670*1ae08745Sheppo 			rv = read_cmd(clientp, prompt, &cmd);
671*1ae08745Sheppo 			/* check error and may exit */
672*1ae08745Sheppo 			console_chk_status(groupp, clientp, rv);
673*1ae08745Sheppo 		}
674*1ae08745Sheppo 
675*1ae08745Sheppo 		switch (cmd) {
676*1ae08745Sheppo 
677*1ae08745Sheppo 		case 'l':
678*1ae08745Sheppo 
679*1ae08745Sheppo 			/* list domain names */
680*1ae08745Sheppo 			rv = list_all_domains(groupp, clientp);
681*1ae08745Sheppo 			break;
682*1ae08745Sheppo 
683*1ae08745Sheppo 
684*1ae08745Sheppo 		case 'q':
685*1ae08745Sheppo 
686*1ae08745Sheppo 			rv = VNTSD_STATUS_CLIENT_QUIT;
687*1ae08745Sheppo 			break;
688*1ae08745Sheppo 
689*1ae08745Sheppo 		case 'h':
690*1ae08745Sheppo 			rv = display_help(clientp);
691*1ae08745Sheppo 			break;
692*1ae08745Sheppo 
693*1ae08745Sheppo 		default:
694*1ae08745Sheppo 			/* select console */
695*1ae08745Sheppo 			if (clientp->cons == NULL) {
696*1ae08745Sheppo 				rv = select_cons(groupp, num_cons,
697*1ae08745Sheppo 				    &consp, clientp, cmd);
698*1ae08745Sheppo 				if (rv == VNTSD_ERR_INVALID_INPUT) {
699*1ae08745Sheppo 					rv = display_help(clientp);
700*1ae08745Sheppo 					break;
701*1ae08745Sheppo 				}
702*1ae08745Sheppo 			} else {
703*1ae08745Sheppo 				consp = clientp->cons;
704*1ae08745Sheppo 			}
705*1ae08745Sheppo 			assert(consp);
706*1ae08745Sheppo 
707*1ae08745Sheppo 			/* connect to console */
708*1ae08745Sheppo 			rv = connect_cons(consp, clientp);
709*1ae08745Sheppo 			D1(stderr, "t@%d console_thread()"
710*1ae08745Sheppo 			    "connect_cons returns %d\n",
711*1ae08745Sheppo 			    thr_self(), rv);
712*1ae08745Sheppo 			break;
713*1ae08745Sheppo 
714*1ae08745Sheppo 		}
715*1ae08745Sheppo 		/* check error and may  exit */
716*1ae08745Sheppo 		console_chk_status(groupp, clientp, rv);
717*1ae08745Sheppo 	}
718*1ae08745Sheppo 
719*1ae08745Sheppo 	/*NOTREACHED*/
720*1ae08745Sheppo 	return (NULL);
721*1ae08745Sheppo }
722