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