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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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