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