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 /*
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * supporting modules.
29 */
30
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <sys/ipc.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <sys/socket.h>
38 #include <sys/ipc.h>
39 #include <sys/shm.h>
40 #include <sys/sem.h>
41 #include <sys/poll.h>
42 #include <wait.h>
43 #include <time.h>
44 #include <netinet/in.h>
45 #include <thread.h>
46 #include <signal.h>
47 #include <ctype.h>
48 #include <langinfo.h>
49 #include <libintl.h>
50 #include <syslog.h>
51 #include "vntsd.h"
52 #include "chars.h"
53
54 /* vntsd_write_line() - write a line to TCP client */
55 int
vntsd_write_line(vntsd_client_t * clientp,char * line)56 vntsd_write_line(vntsd_client_t *clientp, char *line)
57 {
58 int rv;
59
60 rv = vntsd_write_client(clientp, line, strlen(line));
61 if (rv == VNTSD_SUCCESS) {
62 rv = vntsd_write_client(clientp, vntsd_eol, VNTSD_EOL_LEN);
63 }
64
65 return (rv);
66 }
67
68 /* vntsd_write_lines() write one or more lines to client. */
69 int
vntsd_write_lines(vntsd_client_t * clientp,char * lines)70 vntsd_write_lines(vntsd_client_t *clientp, char *lines)
71 {
72 char *buf;
73 char *line;
74 char *endofline;
75
76 buf = strdup(lines);
77 if (buf == NULL) {
78 return (VNTSD_ERR_NO_MEM);
79 }
80
81 line = buf;
82
83 while ((line != NULL) && (*line != '\0')) {
84
85 endofline = strchr(line, '\n');
86 if (endofline != NULL) {
87 *endofline = '\0';
88 }
89
90 (void) vntsd_write_line(clientp, line);
91
92 if (endofline != NULL)
93 line = endofline + 1;
94 else
95 line = NULL;
96 }
97
98 free(buf);
99 return (VNTSD_SUCCESS);
100 }
101
102 /* vntsd_get_yes_no() - read in a "y" or "n" */
103 int
vntsd_get_yes_no(vntsd_client_t * clientp,char * msg,int * yes_no)104 vntsd_get_yes_no(vntsd_client_t *clientp, char *msg, int *yes_no)
105 {
106 char c;
107 char yesno[8];
108 int rv;
109
110 /* create [y/n] prompt */
111 (void) snprintf(yesno, sizeof (yesno), "[%c/%c] ",
112 *nl_langinfo(YESSTR), *nl_langinfo(NOSTR));
113
114 for (; ; ) {
115 if ((rv = vntsd_write_client(clientp, msg, strlen(msg)))
116 != VNTSD_SUCCESS) {
117 return (rv);
118 }
119
120 if ((rv = vntsd_write_client(clientp, yesno, strlen(yesno))) !=
121 VNTSD_SUCCESS) {
122 return (rv);
123 }
124
125 if ((rv = vntsd_read_data(clientp, &c))
126 != VNTSD_SUCCESS) {
127 return (rv);
128 }
129
130 /* echo */
131 if ((rv = vntsd_write_client(clientp, &c, 1)) !=
132 VNTSD_SUCCESS) {
133 return (rv);
134 }
135
136 if ((rv = vntsd_write_client(clientp, vntsd_eol,
137 VNTSD_EOL_LEN)) != VNTSD_SUCCESS) {
138 return (rv);
139 }
140
141 c = tolower(c);
142
143 if (c == *nl_langinfo(YESSTR)) {
144 *yes_no = B_TRUE;
145 return (VNTSD_SUCCESS);
146 }
147
148 if (c == *nl_langinfo(NOSTR)) {
149 *yes_no = B_FALSE;
150 return (VNTSD_SUCCESS);
151 }
152
153 if ((rv = vntsd_write_line(clientp,
154 gettext("Invalid response. Try again.")))
155 != VNTSD_SUCCESS) {
156 return (rv);
157 }
158 }
159
160 /*NOTREACHED*/
161 return (0);
162 }
163
164 /* vntsd_open_vcc() - open a vcc port */
165 int
vntsd_open_vcc(char * dev_name,uint_t cons_no)166 vntsd_open_vcc(char *dev_name, uint_t cons_no)
167 {
168 int drvfd;
169 int sz;
170 char *path;
171 sz = strlen(VCC_DEVICE_PATH) + strlen(dev_name)+1;
172
173 path = calloc(sz, 1);
174
175 if (path == NULL) {
176 return (-1);
177 }
178
179 (void) snprintf(path, sz-1, VCC_DEVICE_PATH, dev_name);
180
181 for (; ; ) {
182 drvfd = open(path, O_RDWR);
183
184 if ((drvfd < 0) && (errno == EAGAIN)) {
185 if (vntsd_vcc_ioctl(VCC_FORCE_CLOSE, cons_no, &cons_no)
186 != VNTSD_SUCCESS) {
187 break;
188 }
189 } else {
190 break;
191 }
192 }
193
194
195 if (drvfd < 0) {
196 D1(stderr, "t@%d open_vcc@%s exit\n", thr_self(), dev_name);
197 free(path);
198 return (-1);
199 }
200
201 free(path);
202 return (drvfd);
203 }
204
205 /* vntsd_cons_by_consno() - match a console structure to cons no */
206 boolean_t
vntsd_cons_by_consno(vntsd_cons_t * consp,int * cons_id)207 vntsd_cons_by_consno(vntsd_cons_t *consp, int *cons_id)
208 {
209 if (consp->status & VNTSD_CONS_DELETED) {
210 return (B_FALSE);
211 }
212 return (consp->cons_no == *cons_id);
213 }
214
215 /* vntsd_write_client() write to telnet client */
216 int
vntsd_write_client(vntsd_client_t * client,char * buffer,size_t sz)217 vntsd_write_client(vntsd_client_t *client, char *buffer, size_t sz)
218 {
219 int rv;
220
221
222 /* write to client */
223 rv = vntsd_write_fd(client->sockfd, buffer, sz);
224
225 /* client has output, reset timer */
226 vntsd_reset_timer(client->cons_tid);
227
228 return (rv);
229 }
230
231 /* vntsd_write_fd() write to tcp socket file descriptor */
232 int
vntsd_write_fd(int fd,void * buf,size_t sz)233 vntsd_write_fd(int fd, void *buf, size_t sz)
234 {
235 int n;
236
237 while (sz > 0) {
238 n = write(fd, buf, sz);
239 if (n < 0) {
240 if (errno == EINTR) {
241 return (VNTSD_STATUS_INTR);
242 }
243
244 return (VNTSD_STATUS_CLIENT_QUIT);
245 }
246
247 if (n == 0) {
248 return (VNTSD_STATUS_CLIENT_QUIT);
249 }
250
251 buf = (caddr_t)buf + n;
252 sz -= n;
253 }
254 return (VNTSD_SUCCESS);
255
256 }
257
258 /*
259 * vntsd_read_char() - read a char from TCP Clienti. Returns:
260 * VNTSD_SUCCESS, VNTSD_STATUS_CLIENT_QUIT or VNTSD_STATUS_INTR
261 */
262 int
vntsd_read_char(vntsd_client_t * clientp,char * c)263 vntsd_read_char(vntsd_client_t *clientp, char *c)
264 {
265 int n;
266 vntsd_timeout_t tmo;
267 int rv;
268
269 tmo.tid = thr_self();
270 tmo.minutes = 0;
271 tmo.clientp = clientp;
272
273 /* attach to timer */
274 if ((rv = vntsd_attach_timer(&tmo)) != VNTSD_SUCCESS) {
275 return (rv);
276 }
277
278 n = read(clientp->sockfd, c, 1);
279
280 /* detach from timer */
281 if ((rv = vntsd_detach_timer(&tmo)) != VNTSD_SUCCESS) {
282 return (rv);
283 }
284
285 if (n == 1) {
286 return (VNTSD_SUCCESS);
287 }
288
289 if (n == 0) {
290 return (VNTSD_STATUS_CLIENT_QUIT);
291 }
292
293 /*
294 * read error or wake up by signal, either console is being removed or
295 * timeout occurs.
296 */
297 if (errno == EINTR) {
298 return (VNTSD_STATUS_INTR);
299 }
300
301 /* any other error, we close client */
302 return (VNTSD_STATUS_CLIENT_QUIT);
303 }
304
305 /*
306 * vntsd_read_data() - handle special commands
307 * such as telnet, daemon and ctrl cmds. Returns:
308 * from vntsd_read_char:
309 * VNTSD_STATUS_CLIENT_QUIT
310 * VNTSD_STATUS_INTR
311 * from vnts_process_daemon_cmd:
312 * VNTSD_STATUS_RESELECT_CONS
313 * VNTSD_STATUS_MOV_CONS_FORWARD
314 * VNTSD_STATUS_MOV_CONS_BACKWARD
315 * VNTSD_STATUS_ACQURE_WRITER
316 * VNTSD_STATUS_CONTINUE
317 * from vntsd_telnet_cmd
318 * VNTSD_STATUS_CONTINUE
319 */
320 int
vntsd_read_data(vntsd_client_t * clientp,char * c)321 vntsd_read_data(vntsd_client_t *clientp, char *c)
322 {
323 int rv;
324
325 for (; ; ) {
326 if ((rv = vntsd_read_char(clientp, c)) != VNTSD_SUCCESS) {
327 return (rv);
328 }
329
330 /* daemon cmd? */
331 rv = vntsd_process_daemon_cmd(clientp, *c);
332
333 if (rv == VNTSD_SUCCESS) {
334 /* telnet cmd? */
335 rv = vntsd_telnet_cmd(clientp, *c);
336 }
337
338 if (rv == VNTSD_STATUS_CONTINUE) {
339 /*
340 * either a daemon cmd or a telnet cmd
341 * was processed.
342 */
343 clientp->prev_char = 0;
344 continue;
345 }
346
347 return (rv);
348 }
349
350 /*NOTREACHED*/
351 return (0);
352 }
353 /* vntsd_read_line() - read a line from TCP client */
354 int
vntsd_read_line(vntsd_client_t * clientp,char * buf,int * in_sz)355 vntsd_read_line(vntsd_client_t *clientp, char *buf, int *in_sz)
356 {
357 char c;
358 int rv;
359 int out_sz = 0;
360
361
362 for (; ; ) {
363
364 if ((rv = vntsd_read_data(clientp, &c)) != VNTSD_SUCCESS) {
365 return (rv);
366 }
367
368 if (c == BS) {
369 /* back */
370 if ((rv = vntsd_write_client(clientp, &c, 1)) !=
371 VNTSD_SUCCESS) {
372 return (rv);
373 }
374
375 c = ' ';
376 if ((rv = vntsd_write_client(clientp, &c, 1)) !=
377 VNTSD_SUCCESS) {
378 return (rv);
379 }
380
381 buf--;
382 out_sz--;
383 continue;
384 }
385 /* echo */
386 if ((rv = vntsd_write_client(clientp, &c, 1)) !=
387 VNTSD_SUCCESS) {
388 return (rv);
389 }
390
391 *buf++ = c;
392 out_sz++;
393
394 if (c == CR) {
395 /* end of line */
396 *in_sz = out_sz;
397 return (VNTSD_SUCCESS);
398 }
399
400 if (out_sz == *in_sz) {
401 return (VNTSD_SUCCESS);
402 }
403 }
404
405 /*NOTREACHED*/
406 return (0);
407 }
408
409 /* free a client */
410 void
vntsd_free_client(vntsd_client_t * clientp)411 vntsd_free_client(vntsd_client_t *clientp)
412 {
413
414 if (clientp->sockfd != -1) {
415 (void) close(clientp->sockfd);
416 }
417
418 (void) mutex_destroy(&clientp->lock);
419
420 free(clientp);
421 }
422
423
424 /* check if a vcc console port still ok */
425 boolean_t
vntsd_vcc_cons_alive(vntsd_cons_t * consp)426 vntsd_vcc_cons_alive(vntsd_cons_t *consp)
427 {
428 vcc_console_t vcc_cons;
429 int rv;
430
431 assert(consp);
432 assert(consp->group);
433
434 /* construct current configuration */
435 (void) strncpy(vcc_cons.domain_name, consp->domain_name, MAXPATHLEN);
436 (void) strncpy(vcc_cons.group_name, consp->group->group_name,
437 MAXPATHLEN);
438 vcc_cons.tcp_port = consp->group->tcp_port;
439 vcc_cons.cons_no = consp->cons_no;
440
441 /* call vcc to verify */
442 rv = vntsd_vcc_ioctl(VCC_CONS_STATUS, consp->cons_no, &vcc_cons);
443 if (rv != VNTSD_SUCCESS) {
444 return (B_FALSE);
445 }
446
447 if (vcc_cons.cons_no == -1) {
448 /* port is gone */
449 return (B_FALSE);
450 }
451
452 /* port is ok */
453 return (B_TRUE);
454
455 }
456
457 /* add to total if a console is alive */
458 static boolean_t
total_cons(vntsd_cons_t * consp,int * num_cons)459 total_cons(vntsd_cons_t *consp, int *num_cons)
460 {
461 int rv;
462
463 assert(consp->group);
464 rv = vntsd_vcc_err(consp);
465 if (rv == VNTSD_STATUS_CONTINUE) {
466 (*num_cons)++;
467 }
468 return (B_FALSE);
469 }
470
471
472 /* total alive consoles in a group */
473 int
vntsd_chk_group_total_cons(vntsd_group_t * groupp)474 vntsd_chk_group_total_cons(vntsd_group_t *groupp)
475 {
476 uint_t num_cons = 0;
477
478 (void) vntsd_que_find(groupp->conspq, (compare_func_t)total_cons,
479 &num_cons);
480 return (num_cons);
481 }
482
483 /* vntsd_log() log function for errors */
484 void
vntsd_log(vntsd_status_t status,char * msg)485 vntsd_log(vntsd_status_t status, char *msg)
486 {
487 char *status_msg = NULL;
488 int critical = 0;
489
490 switch (status) {
491
492 case VNTSD_SUCCESS:
493 status_msg = "STATUS_OK";
494 break;
495
496 case VNTSD_STATUS_CONTINUE:
497 status_msg = "CONTINUE";
498 break;
499
500 case VNTSD_STATUS_EXIT_SIG:
501 critical = 1;
502 status_msg = "KILL SIGNAL RECV";
503 break;
504
505 case VNTSD_STATUS_SIG:
506 status_msg = "SIG RECV";
507 break;
508
509 case VNTSD_STATUS_NO_HOST_NAME:
510 status_msg = "Warining NO HOST NAME";
511 break;
512
513 case VNTSD_STATUS_CLIENT_QUIT:
514 status_msg = "CLIENT CLOSED GROUP CONNECTION";
515 break;
516
517 case VNTSD_STATUS_RESELECT_CONS:
518 status_msg = "CLIENT RESELECTS CONSOLE";
519 break;
520
521 case VNTSD_STATUS_VCC_IO_ERR:
522 status_msg = "CONSOLE WAS DELETED";
523 break;
524
525 case VNTSD_STATUS_MOV_CONS_FORWARD:
526 status_msg = "MOVE CONSOLE FORWARD";
527 break;
528
529 case VNTSD_STATUS_MOV_CONS_BACKWARD:
530 status_msg = "MOVE CONSOLE BACKWARD";
531 break;
532
533 case VNTSD_STATUS_ACQUIRE_WRITER:
534 status_msg = "FORCE CONSOLE WRITE";
535 break;
536
537 case VNTSD_STATUS_INTR:
538 status_msg = "RECV SIGNAL";
539 break;
540
541 case VNTSD_STATUS_DISCONN_CONS:
542 status_msg = "DELETING CONSOLE";
543 break;
544
545 case VNTSD_STATUS_NO_CONS:
546 status_msg = "All console(s) in the group have been deleted.";
547 break;
548
549 case VNTSD_STATUS_AUTH_ENABLED:
550 critical = 1;
551 status_msg = "VNTSD_STATUS_AUTH_ENABLED";
552 break;
553
554 case VNTSD_ERR_NO_MEM:
555 critical = 1;
556 status_msg = "NO MEMORY";
557 break;
558
559 case VNTSD_ERR_NO_DRV:
560 critical = 1;
561 status_msg = "NO VCC DRIVER";
562 break;
563
564 case VNTSD_ERR_WRITE_CLIENT:
565 status_msg = "WRITE CLIENT ERR";
566 break;
567
568 case VNTSD_ERR_EL_NOT_FOUND:
569 critical = 1;
570 status_msg = "ELEMENT_NOT_FOUND";
571 break;
572
573 case VNTSD_ERR_VCC_CTRL_DATA:
574 critical = 1;
575 status_msg = "VCC CTRL DATA ERROR";
576 break;
577
578 case VNTSD_ERR_VCC_POLL:
579 critical = 1;
580 status_msg = "VCC POLL ERROR";
581 break;
582
583 case VNTSD_ERR_VCC_IOCTL:
584 critical = 1;
585 status_msg = "VCC IOCTL ERROR";
586 break;
587
588 case VNTSD_ERR_VCC_GRP_NAME:
589 critical = 1;
590 status_msg = "VCC GROUP NAME ERROR";
591 break;
592
593 case VNTSD_ERR_CREATE_LISTEN_THR:
594 critical = 1;
595 status_msg = "FAIL TO CREATE LISTEN THREAD";
596 break;
597
598 case VNTSD_ERR_CREATE_WR_THR:
599 critical = 1;
600 status_msg = "FAIL TO CREATE WRITE THREAD";
601 break;
602
603 case VNTSD_ERR_ADD_CONS_FAILED:
604 critical = 1;
605 status_msg = "FAIL TO ADD A CONSOLE";
606 break;
607
608 case VNTSD_ERR_LISTEN_SOCKET:
609 critical = 1;
610 status_msg = "LISTEN SOCKET ERROR";
611 break;
612
613 case VNTSD_ERR_LISTEN_OPTS:
614 critical = 1;
615 status_msg = "SET SOCKET OPTIONS ERROR";
616 break;
617
618 case VNTSD_ERR_LISTEN_BIND:
619 critical = 1;
620 status_msg = "BIND SOCKET ERROR";
621 break;
622
623 case VNTSD_STATUS_ACCEPT_ERR:
624 critical = 1;
625 status_msg = "LISTEN ACCEPT ERROR";
626 break;
627
628 case VNTSD_ERR_CREATE_CONS_THR:
629 critical = 1;
630 status_msg = "CREATE CONSOLE THREAD ERROR ";
631 break;
632
633 case VNTSD_ERR_SIG:
634 critical = 1;
635 status_msg = "RECV UNKNOWN SIG";
636 break;
637
638 case VNTSD_ERR_UNKNOWN_CMD:
639 critical = 1;
640 status_msg = "RECV UNKNOWN COMMAND";
641 break;
642
643 case VNTSD_ERR_CLIENT_TIMEOUT:
644 status_msg = "CLOSE CLIENT BECAUSE TIMEOUT";
645 break;
646 default:
647 status_msg = "Unknown status recv";
648 break;
649 }
650
651
652 if (critical) {
653 syslog(LOG_ERR, "%s: thread[%d] %s\n", status_msg,
654 thr_self(), msg);
655 }
656 #ifdef DEBUG
657 DERR(stderr, "%s: thread[%d] %s\n", status_msg, thr_self(), msg);
658 syslog(LOG_ERR, "%s: thread[%d] %s\n", status_msg, thr_self(), msg);
659 #endif
660 }
661