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