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