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 * Configuration and setup interface to vcc driver.
28 * At intialization time, vntsd opens vcc ctrl port and read initial
29 * configuratioa. It manages console groups, creates the listen thread,
30 * dynamically adds and removes virtual console within a group.
31 */
32
33
34 #include <syslog.h>
35 #include <stdio.h>
36 #include <sys/types.h>
37 #include <sys/ipc.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <unistd.h>
41 #include <sys/socket.h>
42 #include <sys/ipc.h>
43 #include <sys/shm.h>
44 #include <sys/sem.h>
45 #include <wait.h>
46 #include <time.h>
47 #include <synch.h>
48 #include <netinet/in.h>
49 #include <thread.h>
50 #include <signal.h>
51 #include "vntsd.h"
52
53 /* signal all clients that console has been deleted */
54 boolean_t
vntsd_notify_client_cons_del(vntsd_client_t * clientp)55 vntsd_notify_client_cons_del(vntsd_client_t *clientp)
56 {
57 (void) mutex_lock(&clientp->lock);
58 clientp->status |= VNTSD_CLIENT_CONS_DELETED;
59 (void) thr_kill(clientp->cons_tid, SIGUSR1);
60 (void) mutex_unlock(&clientp->lock);
61 return (B_FALSE);
62 }
63
64 /* free console structure */
65 static void
free_cons(vntsd_cons_t * consp)66 free_cons(vntsd_cons_t *consp)
67 {
68 assert(consp);
69 (void) mutex_destroy(&consp->lock);
70 (void) cond_destroy(&consp->cvp);
71 if (consp->vcc_fd != -1)
72 (void) close(consp->vcc_fd);
73 free(consp);
74 }
75
76 /* free group structure */
77 static void
free_group(vntsd_group_t * groupp)78 free_group(vntsd_group_t *groupp)
79 {
80 assert(groupp);
81 (void) mutex_destroy(&groupp->lock);
82 (void) cond_destroy(&groupp->cvp);
83 if (groupp->sockfd != -1)
84 (void) close(groupp->sockfd);
85 free(groupp);
86 }
87
88 /*
89 * all clients connected to a console must disconnect before
90 * removing a console.
91 */
92 static void
cleanup_cons(vntsd_cons_t * consp)93 cleanup_cons(vntsd_cons_t *consp)
94 {
95 vntsd_group_t *groupp;
96 timestruc_t to;
97
98 assert(consp);
99 D1(stderr, "t@%d vntsd_disconn_clients@%d\n", thr_self(),
100 consp->cons_no);
101
102 groupp = consp->group;
103 assert(groupp);
104
105
106 (void) mutex_lock(&consp->lock);
107
108 /* wait for all clients disconnect from the console */
109 while (consp->clientpq != NULL) {
110 consp->status |= VNTSD_CONS_SIG_WAIT;
111
112 /* signal client to disconnect the console */
113 (void) vntsd_que_walk(consp->clientpq,
114 (el_func_t)vntsd_notify_client_cons_del);
115
116 (void) thr_kill(consp->wr_tid, SIGUSR1);
117 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
118 to.tv_nsec = 0;
119
120 /* wait for clients to disconnect */
121 (void) cond_reltimedwait(&consp->cvp, &consp->lock, &to);
122 }
123
124 /* reduce console count in the group */
125 (void) mutex_lock(&groupp->lock);
126 assert(groupp->num_cons > 0);
127 groupp->num_cons--;
128 (void) mutex_unlock(&groupp->lock);
129
130 (void) mutex_unlock(&consp->lock);
131
132 free_cons(consp);
133 }
134
135 /* search for a group whose console is being deleted */
136 static boolean_t
find_clean_cons_group(vntsd_group_t * groupp)137 find_clean_cons_group(vntsd_group_t *groupp)
138 {
139 if (groupp->status & VNTSD_GROUP_CLEAN_CONS) {
140 return (B_TRUE);
141 } else {
142 return (B_FALSE);
143 }
144 }
145
146 /* search for a console that is being deleted */
147 static boolean_t
find_clean_cons(vntsd_cons_t * consp)148 find_clean_cons(vntsd_cons_t *consp)
149 {
150 if (consp->status & VNTSD_CONS_DELETED) {
151 return (B_TRUE);
152 } else {
153 return (B_FALSE);
154 }
155 }
156
157 /* delete a console */
158 void
vntsd_delete_cons(vntsd_t * vntsdp)159 vntsd_delete_cons(vntsd_t *vntsdp)
160 {
161 vntsd_group_t *groupp;
162 vntsd_cons_t *consp;
163
164 for (; ; ) {
165 /* get the group contains deleted console */
166 (void) mutex_lock(&vntsdp->lock);
167 groupp = vntsd_que_walk(vntsdp->grouppq,
168 (el_func_t)find_clean_cons_group);
169 if (groupp == NULL) {
170 /* no more group has console deleted */
171 (void) mutex_unlock(&vntsdp->lock);
172 return;
173 }
174 (void) mutex_lock(&groupp->lock);
175 groupp->status &= ~VNTSD_GROUP_CLEAN_CONS;
176 (void) mutex_unlock(&groupp->lock);
177 (void) mutex_unlock(&vntsdp->lock);
178
179 for (; ; ) {
180 /* get the console to be deleted */
181 (void) mutex_lock(&groupp->lock);
182
183 /* clean up any deleted console in the group */
184 if (groupp->conspq != NULL) {
185 consp = vntsd_que_walk(groupp->conspq,
186 (el_func_t)find_clean_cons);
187 if (consp == NULL) {
188 /* no more cons to delete */
189 (void) mutex_unlock(&groupp->lock);
190 break;
191 }
192
193 /* remove console from the group */
194 (void) vntsd_que_rm(&groupp->conspq, consp);
195 (void) mutex_unlock(&groupp->lock);
196
197 /* clean up the console */
198 cleanup_cons(consp);
199 }
200
201 /* delete group? */
202 if (groupp->conspq == NULL) {
203 /* no more console in the group delete group */
204 assert(groupp->vntsd);
205
206 (void) mutex_lock(&groupp->vntsd->lock);
207 (void) vntsd_que_rm(&groupp->vntsd->grouppq,
208 groupp);
209 (void) mutex_unlock(&groupp->vntsd->lock);
210
211 /* clean up the group */
212 vntsd_clean_group(groupp);
213 break;
214 }
215 }
216 }
217 }
218
219 /* clean up a group */
220 void
vntsd_clean_group(vntsd_group_t * groupp)221 vntsd_clean_group(vntsd_group_t *groupp)
222 {
223
224 timestruc_t to;
225
226 D1(stderr, "t@%d clean_group() group=%s tcp=%lld\n", thr_self(),
227 groupp->group_name, groupp->tcp_port);
228
229 (void) mutex_lock(&groupp->lock);
230
231 /* prevent from reentry */
232 if (groupp->status & VNTSD_GROUP_IN_CLEANUP) {
233 (void) mutex_unlock(&groupp->lock);
234 return;
235 }
236 groupp->status |= VNTSD_GROUP_IN_CLEANUP;
237
238 /* mark group waiting for listen thread to exits */
239 groupp->status |= VNTSD_GROUP_SIG_WAIT;
240 (void) mutex_unlock(&groupp->lock);
241
242 vntsd_free_que(&groupp->conspq, (clean_func_t)cleanup_cons);
243
244 (void) mutex_lock(&groupp->lock);
245 /* walk through no cons client queue */
246 while (groupp->no_cons_clientpq != NULL) {
247 (void) vntsd_que_walk(groupp->no_cons_clientpq,
248 (el_func_t)vntsd_notify_client_cons_del);
249 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
250 to.tv_nsec = 0;
251 (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
252 }
253
254 /* waiting for listen thread to exit */
255 while (groupp->status & VNTSD_GROUP_SIG_WAIT) {
256 /* signal listen thread to exit */
257 (void) thr_kill(groupp->listen_tid, SIGUSR1);
258 to.tv_sec = VNTSD_CV_WAIT_DELTIME;
259 to.tv_nsec = 0;
260 /* wait listen thread to exit */
261 (void) cond_reltimedwait(&groupp->cvp, &groupp->lock, &to);
262 }
263
264 (void) mutex_unlock(&groupp->lock);
265 (void) thr_join(groupp->listen_tid, NULL, NULL);
266 /* free group */
267 free_group(groupp);
268 }
269
270 /* allocate and initialize console structure */
271 static vntsd_cons_t *
alloc_cons(vntsd_group_t * groupp,vcc_console_t * consolep)272 alloc_cons(vntsd_group_t *groupp, vcc_console_t *consolep)
273 {
274 vntsd_cons_t *consp;
275 int rv;
276
277 /* allocate console */
278 consp = (vntsd_cons_t *)malloc(sizeof (vntsd_cons_t));
279 if (consp == NULL) {
280 vntsd_log(VNTSD_ERR_NO_MEM, "alloc_cons");
281 return (NULL);
282 }
283
284 /* intialize console */
285 bzero(consp, sizeof (vntsd_cons_t));
286
287 (void) mutex_init(&consp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
288 (void) cond_init(&consp->cvp, USYNC_THREAD, NULL);
289
290 consp->cons_no = consolep->cons_no;
291 (void) strlcpy(consp->domain_name, consolep->domain_name, MAXPATHLEN);
292 (void) strlcpy(consp->dev_name, consolep->dev_name, MAXPATHLEN);
293 consp->wr_tid = (thread_t)-1;
294 consp->vcc_fd = -1;
295
296 /* join the group */
297 (void) mutex_lock(&groupp->lock);
298
299 if ((rv = vntsd_que_append(&groupp->conspq, consp)) !=
300 VNTSD_SUCCESS) {
301 (void) mutex_unlock(&groupp->lock);
302 vntsd_log(rv, "alloc_cons");
303 free_cons(consp);
304 return (NULL);
305 }
306 groupp->num_cons++;
307 consp->group = groupp;
308
309 (void) mutex_unlock(&groupp->lock);
310
311 D1(stderr, "t@%d alloc_cons@%d %s %s\n", thr_self(),
312 consp->cons_no, consp->domain_name, consp->dev_name);
313
314 return (consp);
315 }
316
317 /* compare tcp with group->tcp */
318 static boolean_t
grp_by_tcp(vntsd_group_t * groupp,uint64_t * tcp_port)319 grp_by_tcp(vntsd_group_t *groupp, uint64_t *tcp_port)
320 {
321 assert(groupp);
322 assert(tcp_port);
323 return (groupp->tcp_port == *tcp_port);
324 }
325
326 /* allocate and initialize group */
327 static vntsd_group_t *
alloc_group(vntsd_t * vntsdp,char * group_name,uint64_t tcp_port)328 alloc_group(vntsd_t *vntsdp, char *group_name, uint64_t tcp_port)
329 {
330 vntsd_group_t *groupp;
331
332 /* allocate group */
333 groupp = (vntsd_group_t *)malloc(sizeof (vntsd_group_t));
334 if (groupp == NULL) {
335 vntsd_log(VNTSD_ERR_NO_MEM, "alloc_group");
336 return (NULL);
337 }
338
339 /* initialize group */
340 bzero(groupp, sizeof (vntsd_group_t));
341
342 (void) mutex_init(&groupp->lock, USYNC_THREAD|LOCK_ERRORCHECK, NULL);
343 (void) cond_init(&groupp->cvp, USYNC_THREAD, NULL);
344
345 if (group_name != NULL) {
346 (void) memcpy(groupp->group_name, group_name, MAXPATHLEN);
347 }
348
349 groupp->tcp_port = tcp_port;
350 groupp->listen_tid = (thread_t)-1;
351 groupp->sockfd = -1;
352 groupp->vntsd = vntsdp;
353
354 D1(stderr, "t@%d alloc_group@%lld:%s\n", thr_self(), groupp->tcp_port,
355 groupp->group_name);
356
357 return (groupp);
358 }
359
360 /* mark a deleted console */
361 boolean_t
vntsd_mark_deleted_cons(vntsd_cons_t * consp)362 vntsd_mark_deleted_cons(vntsd_cons_t *consp)
363 {
364 (void) mutex_lock(&consp->lock);
365 consp->status |= VNTSD_CONS_DELETED;
366 (void) mutex_unlock(&consp->lock);
367 return (B_FALSE);
368 }
369
370 /*
371 * Initialize a console, if console is associated with with a
372 * new group, intialize the group.
373 */
374 static int
alloc_cons_with_group(vntsd_t * vntsdp,vcc_console_t * consp,vntsd_group_t ** new_groupp)375 alloc_cons_with_group(vntsd_t *vntsdp, vcc_console_t *consp,
376 vntsd_group_t **new_groupp)
377 {
378 vntsd_group_t *groupp = NULL;
379 int rv;
380
381 *new_groupp = NULL;
382
383 /* match group by tcp port */
384
385
386 (void) mutex_lock(&vntsdp->lock);
387 groupp = vntsd_que_find(vntsdp->grouppq,
388 (compare_func_t)grp_by_tcp, (void *)&(consp->tcp_port));
389 if (groupp != NULL)
390 (void) mutex_lock(&groupp->lock);
391
392 (void) mutex_unlock(&vntsdp->lock);
393
394 if (groupp != NULL) {
395 /*
396 * group with same tcp port found.
397 * if there is no console in the group, the
398 * group should be removed and the tcp port can
399 * be used for tne new group.
400 * This is possible, when there is tight loop of
401 * creating/deleting domains. When a vcc port is
402 * removed, a read thread will have an I/O error because
403 * vcc has closed the port. The read thread then marks
404 * the console is removed and notify main thread to
405 * remove the console.
406 * Meanwhile, the same port and its group (with same
407 * tcp port and group name) is created. Vcc notify
408 * vntsd that new console is added.
409 * Main thread now have two events. If main thread polls
410 * out vcc notification first, it will find that there is
411 * a group has no console.
412 */
413
414 if (vntsd_chk_group_total_cons(groupp) == 0) {
415
416 /* all consoles in the group have been removed */
417 (void) vntsd_que_walk(groupp->conspq,
418 (el_func_t)vntsd_mark_deleted_cons);
419 groupp->status |= VNTSD_GROUP_CLEAN_CONS;
420 (void) mutex_unlock(&groupp->lock);
421 groupp = NULL;
422
423 } else if (strcmp(groupp->group_name, consp->group_name)) {
424 /* conflict group name */
425 vntsd_log(VNTSD_ERR_VCC_GRP_NAME,
426 "group name is different from existing group");
427 (void) mutex_unlock(&groupp->lock);
428 return (VNTSD_ERR_VCC_CTRL_DATA);
429
430 } else {
431 /* group already existed */
432 (void) mutex_unlock(&groupp->lock);
433 }
434
435 }
436
437 if (groupp == NULL) {
438 /* new group */
439 groupp = alloc_group(vntsdp, consp->group_name,
440 consp->tcp_port);
441 if (groupp == NULL) {
442 return (VNTSD_ERR_NO_MEM);
443 }
444
445 assert(groupp->conspq == NULL);
446 /* queue group to vntsdp */
447 (void) mutex_lock(&vntsdp->lock);
448 rv = vntsd_que_append(&vntsdp->grouppq, groupp);
449 (void) mutex_unlock(&vntsdp->lock);
450
451 if (rv != VNTSD_SUCCESS) {
452 return (rv);
453 }
454
455 *new_groupp = groupp;
456 }
457
458 /* intialize console */
459 if (alloc_cons(groupp, consp) == NULL) {
460 /* no memory */
461 if (*new_groupp != NULL) {
462 /* clean up new group */
463 free_group(groupp);
464 }
465
466 return (VNTSD_ERR_NO_MEM);
467 }
468
469 return (VNTSD_SUCCESS);
470
471 }
472
473
474 /* create listen thread */
475 static boolean_t
create_listen_thread(vntsd_group_t * groupp)476 create_listen_thread(vntsd_group_t *groupp)
477 {
478
479 char err_msg[VNTSD_LINE_LEN];
480 int rv;
481
482 assert(groupp);
483
484 (void) mutex_lock(&groupp->lock);
485 assert(groupp->num_cons);
486
487 D1(stderr, "t@%d create_listen:%lld\n", thr_self(), groupp->tcp_port);
488
489 if ((rv = thr_create(NULL, 0, (thr_func_t)vntsd_listen_thread,
490 (void *)groupp, THR_DETACHED, &groupp->listen_tid)) != 0) {
491 (void) (void) snprintf(err_msg, sizeof (err_msg),
492 "Can not create listen thread for"
493 "group %s tcp %llx\n", groupp->group_name,
494 groupp->tcp_port);
495 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, err_msg);
496
497 /* clean up group queue */
498 vntsd_free_que(&groupp->conspq, (clean_func_t)free_cons);
499 groupp->listen_tid = (thread_t)-1;
500 }
501
502 (void) mutex_unlock(&groupp->lock);
503
504 return (rv != 0);
505 }
506
507 /* find deleted console by console no */
508 static boolean_t
deleted_cons_by_consno(vntsd_cons_t * consp,int * cons_no)509 deleted_cons_by_consno(vntsd_cons_t *consp, int *cons_no)
510 {
511 vntsd_client_t *clientp;
512
513 assert(consp);
514
515 if (consp->cons_no != *cons_no)
516 return (B_FALSE);
517
518 /* has console marked as deleted? */
519 if ((consp->status & VNTSD_CONS_DELETED) == 0)
520 return (B_TRUE);
521
522 if (consp->clientpq == NULL)
523 /* there is no client for this console */
524 return (B_TRUE);
525
526 /* need to notify clients of console ? */
527 clientp = (vntsd_client_t *)consp->clientpq->handle;
528
529 if (clientp->status & VNTSD_CLIENT_CONS_DELETED)
530 /* clients of console have notified */
531 return (B_FALSE);
532
533 return (B_TRUE);
534 }
535
536 /* find group structure from console no */
537 static boolean_t
find_cons_group_by_cons_no(vntsd_group_t * groupp,uint_t * cons_no)538 find_cons_group_by_cons_no(vntsd_group_t *groupp, uint_t *cons_no)
539 {
540 vntsd_cons_t *consp;
541
542 consp = vntsd_que_find(groupp->conspq,
543 (compare_func_t)deleted_cons_by_consno, cons_no);
544 return (consp != NULL);
545
546 }
547
548 /* delete a console if the console exists in the vntsd */
549 static void
delete_cons_before_add(vntsd_t * vntsdp,uint_t cons_no)550 delete_cons_before_add(vntsd_t *vntsdp, uint_t cons_no)
551 {
552 vntsd_group_t *groupp;
553 vntsd_cons_t *consp;
554
555 /* group exists? */
556 (void) mutex_lock(&vntsdp->lock);
557 groupp = vntsd_que_find(vntsdp->grouppq,
558 (compare_func_t)find_cons_group_by_cons_no,
559 &cons_no);
560 (void) mutex_unlock(&vntsdp->lock);
561
562 if (groupp == NULL) {
563 /* no such group */
564 return;
565 }
566
567 /* group exists, if console exists? */
568 (void) mutex_lock(&groupp->lock);
569 consp = vntsd_que_find(groupp->conspq,
570 (compare_func_t)deleted_cons_by_consno, &cons_no);
571
572 if (consp == NULL) {
573 /* no such console */
574 (void) mutex_unlock(&groupp->lock);
575 return;
576 }
577
578 /* console exists - mark console for main thread to delete it */
579 (void) mutex_lock(&consp->lock);
580
581 if (consp->status & VNTSD_CONS_DELETED) {
582 /* already marked */
583 (void) mutex_unlock(&consp->lock);
584 (void) mutex_unlock(&groupp->lock);
585 return;
586 }
587
588 consp->status |= VNTSD_CONS_DELETED;
589 groupp->status |= VNTSD_GROUP_CLEAN_CONS;
590
591 (void) mutex_unlock(&consp->lock);
592 (void) mutex_unlock(&groupp->lock);
593
594 }
595
596 /* add a console */
597 static void
do_add_cons(vntsd_t * vntsdp,int cons_no)598 do_add_cons(vntsd_t *vntsdp, int cons_no)
599 {
600 vcc_console_t console;
601 vntsd_group_t *groupp;
602 int rv;
603 char err_msg[VNTSD_LINE_LEN];
604
605
606 (void) snprintf(err_msg, sizeof (err_msg),
607 "do_add_cons():Can not add console=%d", cons_no);
608
609 /* get console configuration from vcc */
610
611 if ((rv = vntsd_vcc_ioctl(VCC_CONS_INFO, cons_no, (void *)&console))
612 != VNTSD_SUCCESS) {
613 vntsd_log(rv, err_msg);
614 return;
615 }
616
617 /* clean up the console if console was deleted and added again */
618 delete_cons_before_add(vntsdp, console.cons_no);
619
620 /* initialize console */
621
622 if ((rv = alloc_cons_with_group(vntsdp, &console, &groupp)) !=
623 VNTSD_SUCCESS) {
624 /* no memory to add this new console */
625 vntsd_log(rv, err_msg);
626 return;
627 }
628
629 if (groupp != NULL) {
630 /* new group */
631 /* create listen thread for this console */
632 if (create_listen_thread(groupp)) {
633 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, err_msg);
634 free_group(groupp);
635 }
636
637 }
638 }
639
640 /* daemon wake up */
641 void
vntsd_daemon_wakeup(vntsd_t * vntsdp)642 vntsd_daemon_wakeup(vntsd_t *vntsdp)
643 {
644
645 vcc_response_t inq_data;
646
647 /* reason to wake up */
648 if (vntsd_vcc_ioctl(VCC_INQUIRY, 0, (void *)&inq_data) !=
649 VNTSD_SUCCESS) {
650 vntsd_log(VNTSD_ERR_VCC_IOCTL, "vntsd_daemon_wakeup()");
651 return;
652 }
653
654 D1(stderr, "t@%d vntsd_daemon_wakup:msg %d port %x\n", thr_self(),
655 inq_data.reason, inq_data.cons_no);
656
657 switch (inq_data.reason) {
658
659 case VCC_CONS_ADDED:
660 do_add_cons(vntsdp, inq_data.cons_no);
661 break;
662
663 case VCC_CONS_MISS_ADDED:
664 /* an added port was deleted before vntsd can process it */
665 return;
666
667 default:
668 DERR(stderr, "t@%d daemon_wakeup:ioctl_unknown %d\n",
669 thr_self(), inq_data.reason);
670 vntsd_log(VNTSD_ERR_UNKNOWN_CMD, "from vcc\n");
671 break;
672 }
673 }
674
675 /* initial console configuration */
676 void
vntsd_get_config(vntsd_t * vntsdp)677 vntsd_get_config(vntsd_t *vntsdp)
678 {
679
680 int i;
681 int num_cons;
682 vcc_console_t *consp;
683 vntsd_group_t *groupp;
684
685 /* num of consoles */
686 num_cons = 0;
687
688 if (vntsd_vcc_ioctl(VCC_NUM_CONSOLE, 0, (void *)&num_cons) !=
689 VNTSD_SUCCESS) {
690 vntsd_log(VNTSD_ERR_VCC_IOCTL, "VCC_NUM_CONSOLE failed\n");
691 return;
692 }
693
694 D3(stderr, "get_config:num_cons=%d", num_cons);
695
696 if (num_cons == 0) {
697 return;
698 }
699
700 /* allocate memory for all consoles */
701 consp = malloc(num_cons*sizeof (vcc_console_t));
702
703 if (consp == NULL) {
704 vntsd_log(VNTSD_ERR_NO_MEM, "for console table.");
705 return;
706 }
707
708 /* get console table */
709 if (vntsd_vcc_ioctl(VCC_CONS_TBL, 0, (void *)consp) != VNTSD_SUCCESS) {
710 vntsd_log(VNTSD_ERR_VCC_IOCTL, " VCC_CONS_TBL "
711 "for console table\n");
712 return;
713 }
714
715 /* intialize groups and consoles */
716 for (i = 0; i < num_cons; i++) {
717 if (alloc_cons_with_group(vntsdp, &consp[i], &groupp)
718 != VNTSD_SUCCESS) {
719 vntsd_log(VNTSD_ERR_ADD_CONS_FAILED, "get_config");
720 }
721 }
722
723 /* create listen thread for each group */
724 (void) mutex_lock(&vntsdp->lock);
725
726 for (; ; ) {
727 groupp = vntsd_que_walk(vntsdp->grouppq,
728 (el_func_t)create_listen_thread);
729 if (groupp == NULL) {
730 break;
731 }
732 vntsd_log(VNTSD_ERR_CREATE_LISTEN_THR, "get config()");
733 }
734
735 (void) mutex_unlock(&vntsdp->lock);
736 }
737