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