1 /** 2 * Console server process for OpenBMC 3 * 4 * Copyright © 2016 IBM Corporation 5 * 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 19 #define _GNU_SOURCE 20 21 #include <assert.h> 22 #include <errno.h> 23 #include <signal.h> 24 #include <stdint.h> 25 #include <stdbool.h> 26 #include <stdlib.h> 27 #include <stdio.h> 28 #include <fcntl.h> 29 #include <unistd.h> 30 #include <err.h> 31 #include <string.h> 32 #include <getopt.h> 33 #include <limits.h> 34 #include <time.h> 35 #include <termios.h> 36 37 #include <sys/types.h> 38 #include <sys/time.h> 39 #include <poll.h> 40 41 #include "console-server.h" 42 43 #define DBUS_ERR "org.openbmc.error" 44 #define DBUS_NAME "xyz.openbmc_project.console" 45 #define OBJ_NAME "/xyz/openbmc_project/console" 46 47 struct console { 48 const char *tty_kname; 49 char *tty_sysfs_devnode; 50 char *tty_dev; 51 int tty_sirq; 52 int tty_lpc_addr; 53 speed_t tty_baud; 54 int tty_fd; 55 56 struct ringbuffer *rb; 57 58 struct handler **handlers; 59 int n_handlers; 60 61 struct poller **pollers; 62 int n_pollers; 63 64 struct pollfd *pollfds; 65 struct sd_bus *bus; 66 }; 67 68 struct poller { 69 struct handler *handler; 70 void *data; 71 poller_event_fn_t event_fn; 72 poller_timeout_fn_t timeout_fn; 73 struct timeval timeout; 74 bool remove; 75 }; 76 77 /* we have two extra entry in the pollfds array for the VUART tty */ 78 enum internal_pollfds { 79 POLLFD_HOSTTTY = 0, 80 POLLFD_DBUS = 1, 81 MAX_INTERNAL_POLLFD = 2, 82 }; 83 84 /* size of the shared backlog ringbuffer */ 85 const size_t buffer_size = 128 * 1024; 86 87 /* state shared with the signal handler */ 88 static bool sigint; 89 90 static void usage(const char *progname) 91 { 92 fprintf(stderr, 93 "usage: %s [options] <DEVICE>\n" 94 "\n" 95 "Options:\n" 96 " --config <FILE> Use FILE for configuration\n" 97 "", 98 progname); 99 } 100 101 /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 102 static int tty_find_device(struct console *console) 103 { 104 char *tty_class_device_link; 105 char *tty_device_tty_dir; 106 char *tty_device_reldir; 107 char *tty_path_input; 108 char *tty_path_input_real; 109 char *tty_kname_real; 110 int rc; 111 112 tty_class_device_link = NULL; 113 tty_device_tty_dir = NULL; 114 tty_device_reldir = NULL; 115 tty_path_input = NULL; 116 tty_path_input_real = NULL; 117 tty_kname_real = NULL; 118 119 /* udev may rename the tty name with a symbol link, try to resolve */ 120 rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname); 121 if (rc < 0) 122 return -1; 123 124 tty_path_input_real = realpath(tty_path_input, NULL); 125 if (!tty_path_input_real) { 126 warn("Can't find realpath for /dev/%s", console->tty_kname); 127 goto out_free; 128 } 129 130 tty_kname_real = basename(tty_path_input_real); 131 if (!tty_kname_real) { 132 warn("Can't find real name for /dev/%s", console->tty_kname); 133 goto out_free; 134 } 135 136 rc = asprintf(&tty_class_device_link, 137 "/sys/class/tty/%s", tty_kname_real); 138 if (rc < 0) 139 goto out_free; 140 141 tty_device_tty_dir = realpath(tty_class_device_link, NULL); 142 if (!tty_device_tty_dir) { 143 warn("Can't query sysfs for device %s", tty_kname_real); 144 goto out_free; 145 } 146 147 rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 148 if (rc < 0) 149 goto out_free; 150 151 console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 152 if (!console->tty_sysfs_devnode) 153 warn("Can't find parent device for %s", tty_kname_real); 154 155 rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 156 if (rc < 0) 157 goto out_free; 158 159 rc = 0; 160 161 out_free: 162 free(tty_class_device_link); 163 free(tty_device_tty_dir); 164 free(tty_device_reldir); 165 free(tty_path_input); 166 free(tty_path_input_real); 167 return rc; 168 } 169 170 static int tty_set_sysfs_attr(struct console *console, const char *name, 171 int value) 172 { 173 char *path; 174 FILE *fp; 175 int rc; 176 177 rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 178 if (rc < 0) 179 return -1; 180 181 fp = fopen(path, "w"); 182 if (!fp) { 183 warn("Can't access attribute %s on device %s", 184 name, console->tty_kname); 185 rc = -1; 186 goto out_free; 187 } 188 setvbuf(fp, NULL, _IONBF, 0); 189 190 rc = fprintf(fp, "0x%x", value); 191 if (rc < 0) 192 warn("Error writing to %s attribute of device %s", 193 name, console->tty_kname); 194 fclose(fp); 195 196 197 198 out_free: 199 free(path); 200 return rc; 201 } 202 203 /** 204 * Set termios attributes on the console tty. 205 */ 206 static void tty_init_termios(struct console *console) 207 { 208 struct termios termios; 209 int rc; 210 211 rc = tcgetattr(console->tty_fd, &termios); 212 if (rc) { 213 warn("Can't read tty termios"); 214 return; 215 } 216 217 if (console->tty_baud) { 218 if (cfsetspeed(&termios, console->tty_baud) < 0) 219 warn("Couldn't set speeds for %s", console->tty_kname); 220 } 221 222 /* Set console to raw mode: we don't want any processing to occur on 223 * the underlying terminal input/output. 224 */ 225 cfmakeraw(&termios); 226 227 rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 228 if (rc) 229 warn("Can't set terminal options for %s", console->tty_kname); 230 } 231 232 233 static void tty_change_baudrate(struct console *console) 234 { 235 struct handler *handler; 236 int i, rc; 237 238 tty_init_termios(console); 239 240 for (i = 0; i < console->n_handlers; i++) { 241 handler = console->handlers[i]; 242 if (!handler->baudrate) 243 continue; 244 245 rc = handler->baudrate(handler, console->tty_baud); 246 if (rc) 247 warnx("Can't set terminal baudrate for handler %s", 248 handler->name); 249 } 250 } 251 252 /** 253 * Open and initialise the serial device 254 */ 255 static int tty_init_io(struct console *console) 256 { 257 if (console->tty_sirq) 258 tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 259 if (console->tty_lpc_addr) 260 tty_set_sysfs_attr(console, "lpc_address", 261 console->tty_lpc_addr); 262 263 console->tty_fd = open(console->tty_dev, O_RDWR); 264 if (console->tty_fd <= 0) { 265 warn("Can't open tty %s", console->tty_dev); 266 return -1; 267 } 268 269 /* Disable character delay. We may want to later enable this when 270 * we detect larger amounts of data 271 */ 272 fcntl(console->tty_fd, F_SETFL, FNDELAY); 273 274 tty_init_termios(console); 275 276 console->pollfds[console->n_pollers].fd = console->tty_fd; 277 console->pollfds[console->n_pollers].events = POLLIN; 278 279 return 0; 280 } 281 282 static int tty_init(struct console *console, struct config *config) 283 { 284 const char *val; 285 char *endp; 286 int rc; 287 288 val = config_get_value(config, "lpc-address"); 289 if (val) { 290 console->tty_lpc_addr = strtoul(val, &endp, 0); 291 if (endp == optarg) { 292 warn("Invalid LPC address: '%s'", val); 293 return -1; 294 } 295 } 296 297 val = config_get_value(config, "sirq"); 298 if (val) { 299 console->tty_sirq = strtoul(val, &endp, 0); 300 if (endp == optarg) 301 warn("Invalid sirq: '%s'", val); 302 } 303 304 val = config_get_value(config, "baud"); 305 if (val) { 306 if (config_parse_baud(&console->tty_baud, val)) 307 warnx("Invalid baud rate: '%s'", val); 308 } 309 310 if (!console->tty_kname) { 311 warnx("Error: No TTY device specified"); 312 return -1; 313 } 314 315 rc = tty_find_device(console); 316 if (rc) 317 return rc; 318 319 rc = tty_init_io(console); 320 return rc; 321 } 322 323 324 int console_data_out(struct console *console, const uint8_t *data, size_t len) 325 { 326 return write_buf_to_fd(console->tty_fd, data, len); 327 } 328 329 static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 330 sd_bus_error *err) 331 { 332 struct console *console = userdata; 333 uint32_t baudrate; 334 speed_t speed; 335 int r; 336 337 if (!console) { 338 sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 339 return sd_bus_reply_method_return(msg, "x", 0); 340 } 341 342 r = sd_bus_message_read(msg, "u", &baudrate); 343 if (r < 0) { 344 sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 345 return sd_bus_reply_method_return(msg, "x", -EINVAL); 346 } 347 348 speed = parse_int_to_baud(baudrate); 349 if (!speed) { 350 warnx("Invalid baud rate: '%u'", baudrate); 351 return sd_bus_reply_method_return(msg, "x", -EINVAL); 352 } 353 354 console->tty_baud = speed; 355 tty_change_baudrate(console); 356 357 return sd_bus_reply_method_return(msg, "x", r); 358 } 359 360 static int get_handler(sd_bus *bus, const char *path, const char *interface, 361 const char *property, sd_bus_message *reply, void *userdata, 362 sd_bus_error *error) { 363 struct console *console = userdata; 364 uint32_t baudrate; 365 int r; 366 367 baudrate = parse_baud_to_int(console->tty_baud); 368 if (!baudrate) 369 warnx("Invalid baud rate: '%d'", console->tty_baud); 370 371 r = sd_bus_message_append(reply, "u", baudrate); 372 373 return r; 374 } 375 376 static const sd_bus_vtable console_vtable[] = { 377 SD_BUS_VTABLE_START(0), 378 SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 379 SD_BUS_VTABLE_UNPRIVILEGED), 380 SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 381 SD_BUS_VTABLE_END,}; 382 383 static void dbus_init(struct console *console, struct config *config) 384 { 385 int dbus_poller = 0; 386 int fd, r; 387 388 if (!console) { 389 warnx("Couldn't get valid console"); 390 return; 391 } 392 393 r = sd_bus_default_system(&console->bus); 394 if (r < 0) { 395 warnx("Failed to connect to system bus: %s", strerror(-r)); 396 return; 397 } 398 399 r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 400 console_vtable, console); 401 if (r < 0) { 402 warnx("Failed to issue method call: %s", strerror(-r)); 403 return; 404 } 405 406 r = sd_bus_request_name(console->bus, DBUS_NAME, SD_BUS_NAME_ALLOW_REPLACEMENT 407 |SD_BUS_NAME_REPLACE_EXISTING); 408 if (r < 0) { 409 warnx("Failed to acquire service name: %s", strerror(-r)); 410 return; 411 } 412 413 fd = sd_bus_get_fd(console->bus); 414 if (fd < 0) { 415 warnx("Couldn't get the bus file descriptor"); 416 return; 417 } 418 419 dbus_poller = POLLFD_DBUS; 420 421 console->pollfds[dbus_poller].fd = fd; 422 console->pollfds[dbus_poller].events = POLLIN; 423 } 424 425 static void handlers_init(struct console *console, struct config *config) 426 { 427 extern struct handler *__start_handlers, *__stop_handlers; 428 struct handler *handler; 429 int i, rc; 430 431 console->n_handlers = &__stop_handlers - &__start_handlers; 432 console->handlers = &__start_handlers; 433 434 printf("%d handler%s\n", console->n_handlers, 435 console->n_handlers == 1 ? "" : "s"); 436 437 for (i = 0; i < console->n_handlers; i++) { 438 handler = console->handlers[i]; 439 440 rc = 0; 441 if (handler->init) 442 rc = handler->init(handler, console, config); 443 444 handler->active = rc == 0; 445 446 printf(" %s [%sactive]\n", handler->name, 447 handler->active ? "" : "in"); 448 } 449 } 450 451 static void handlers_fini(struct console *console) 452 { 453 struct handler *handler; 454 int i; 455 456 for (i = 0; i < console->n_handlers; i++) { 457 handler = console->handlers[i]; 458 if (handler->fini && handler->active) 459 handler->fini(handler); 460 } 461 } 462 463 static int get_current_time(struct timeval *tv) 464 { 465 struct timespec t; 466 int rc; 467 468 /* 469 * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 470 * local time changes. However, a struct timeval is more 471 * convenient for calculations, so convert to that. 472 */ 473 rc = clock_gettime(CLOCK_MONOTONIC, &t); 474 if (rc) 475 return rc; 476 477 tv->tv_sec = t.tv_sec; 478 tv->tv_usec = t.tv_nsec / 1000; 479 480 return 0; 481 } 482 483 struct ringbuffer_consumer *console_ringbuffer_consumer_register( 484 struct console *console, 485 ringbuffer_poll_fn_t poll_fn, void *data) 486 { 487 return ringbuffer_consumer_register(console->rb, poll_fn, data); 488 } 489 490 struct poller *console_poller_register(struct console *console, 491 struct handler *handler, poller_event_fn_t poller_fn, 492 poller_timeout_fn_t timeout_fn, int fd, 493 int events, void *data) 494 { 495 struct poller *poller; 496 int n; 497 498 poller = malloc(sizeof(*poller)); 499 poller->remove = false; 500 poller->handler = handler; 501 poller->event_fn = poller_fn; 502 poller->timeout_fn = timeout_fn; 503 poller->data = data; 504 505 /* add one to our pollers array */ 506 n = console->n_pollers++; 507 console->pollers = realloc(console->pollers, 508 sizeof(*console->pollers) * console->n_pollers); 509 510 console->pollers[n] = poller; 511 512 /* increase pollfds array too */ 513 console->pollfds = realloc(console->pollfds, 514 sizeof(*console->pollfds) * 515 (MAX_INTERNAL_POLLFD + console->n_pollers)); 516 517 /* shift the end pollfds up by one */ 518 memcpy(&console->pollfds[n+1], 519 &console->pollfds[n], 520 sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 521 522 console->pollfds[n].fd = fd; 523 console->pollfds[n].events = events; 524 525 return poller; 526 } 527 528 void console_poller_unregister(struct console *console, 529 struct poller *poller) 530 { 531 int i; 532 533 /* find the entry in our pollers array */ 534 for (i = 0; i < console->n_pollers; i++) 535 if (console->pollers[i] == poller) 536 break; 537 538 assert(i < console->n_pollers); 539 540 console->n_pollers--; 541 542 /* remove the item from the pollers array... */ 543 memmove(&console->pollers[i], &console->pollers[i+1], 544 sizeof(*console->pollers) 545 * (console->n_pollers - i)); 546 547 console->pollers = realloc(console->pollers, 548 sizeof(*console->pollers) * console->n_pollers); 549 550 /* ... and the pollfds array */ 551 memmove(&console->pollfds[i], &console->pollfds[i+1], 552 sizeof(*console->pollfds) * 553 (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 554 555 console->pollfds = realloc(console->pollfds, 556 sizeof(*console->pollfds) * 557 (MAX_INTERNAL_POLLFD + console->n_pollers)); 558 559 560 free(poller); 561 } 562 563 void console_poller_set_events(struct console *console, struct poller *poller, 564 int events) 565 { 566 int i; 567 568 /* find the entry in our pollers array */ 569 for (i = 0; i < console->n_pollers; i++) 570 if (console->pollers[i] == poller) 571 break; 572 573 console->pollfds[i].events = events; 574 } 575 576 void console_poller_set_timeout(struct console *console, struct poller *poller, 577 const struct timeval *tv) 578 { 579 struct timeval now; 580 int rc; 581 582 rc = get_current_time(&now); 583 if (rc) 584 return; 585 586 timeradd(&now, tv, &poller->timeout); 587 } 588 589 static int get_poll_timeout(struct console *console, struct timeval *cur_time) 590 { 591 struct timeval *earliest, interval; 592 struct poller *poller; 593 int i; 594 595 earliest = NULL; 596 597 for (i = 0; i < console->n_pollers; i++) { 598 poller = console->pollers[i]; 599 600 if (poller->timeout_fn && timerisset(&poller->timeout) && 601 (!earliest || 602 (earliest && timercmp(&poller->timeout, earliest, <)))){ 603 // poller is buffering data and needs the poll 604 // function to timeout. 605 earliest = &poller->timeout; 606 } 607 } 608 609 if (earliest) { 610 if (timercmp(earliest, cur_time, >)) { 611 /* recalculate the timeout period, time period has 612 * not elapsed */ 613 timersub(earliest, cur_time, &interval); 614 return ((interval.tv_sec * 1000) + 615 (interval.tv_usec / 1000)); 616 } else { 617 /* return from poll immediately */ 618 return 0; 619 } 620 } else { 621 /* poll indefinitely */ 622 return -1; 623 } 624 } 625 626 static int call_pollers(struct console *console, struct timeval *cur_time) 627 { 628 struct poller *poller; 629 struct pollfd *pollfd; 630 enum poller_ret prc; 631 int i, rc; 632 633 rc = 0; 634 635 /* 636 * Process poll events by iterating through the pollers and pollfds 637 * in-step, calling any pollers that we've found revents for. 638 */ 639 for (i = 0; i < console->n_pollers; i++) { 640 poller = console->pollers[i]; 641 pollfd = &console->pollfds[i]; 642 prc = POLLER_OK; 643 644 /* process pending events... */ 645 if (pollfd->revents) { 646 prc = poller->event_fn(poller->handler, pollfd->revents, 647 poller->data); 648 if (prc == POLLER_EXIT) 649 rc = -1; 650 else if (prc == POLLER_REMOVE) 651 poller->remove = true; 652 } 653 654 if ((prc == POLLER_OK) && poller->timeout_fn && 655 timerisset(&poller->timeout) && 656 timercmp(&poller->timeout, cur_time, <=)) { 657 /* One of the ringbuffer consumers is buffering the 658 data stream. The amount of idle time the consumer 659 desired has expired. Process the buffered data for 660 transmission. */ 661 timerclear(&poller->timeout); 662 prc = poller->timeout_fn(poller->handler, poller->data); 663 if (prc == POLLER_EXIT) { 664 rc = -1; 665 } else if (prc == POLLER_REMOVE) { 666 poller->remove = true; 667 } 668 } 669 } 670 671 /** 672 * Process deferred removals; restarting each time we unregister, as 673 * the array will have changed 674 */ 675 for (;;) { 676 bool removed = false; 677 678 for (i = 0; i < console->n_pollers; i++) { 679 poller = console->pollers[i]; 680 if (poller->remove) { 681 console_poller_unregister(console, poller); 682 removed = true; 683 break; 684 } 685 } 686 if (!removed) 687 break; 688 } 689 690 return rc; 691 } 692 693 static void sighandler(int signal) 694 { 695 if (signal == SIGINT) 696 sigint = true; 697 } 698 699 int run_console(struct console *console) 700 { 701 sighandler_t sighandler_save; 702 struct timeval tv; 703 int rc, timeout; 704 705 sighandler_save = signal(SIGINT, sighandler); 706 707 rc = 0; 708 709 for (;;) { 710 uint8_t buf[4096]; 711 712 BUILD_ASSERT(sizeof(buf) <= buffer_size); 713 714 if (sigint) { 715 fprintf(stderr, "Received interrupt, exiting\n"); 716 break; 717 } 718 719 rc = get_current_time(&tv); 720 if (rc) { 721 warn("Failed to read current time"); 722 break; 723 } 724 725 timeout = get_poll_timeout(console, &tv); 726 727 rc = poll(console->pollfds, 728 console->n_pollers + MAX_INTERNAL_POLLFD, 729 timeout); 730 731 if (rc < 0) { 732 if (errno == EINTR) { 733 continue; 734 } else { 735 warn("poll error"); 736 break; 737 } 738 } 739 740 /* process internal fd first */ 741 if (console->pollfds[console->n_pollers].revents) { 742 rc = read(console->tty_fd, buf, sizeof(buf)); 743 if (rc <= 0) { 744 warn("Error reading from tty device"); 745 rc = -1; 746 break; 747 } 748 rc = ringbuffer_queue(console->rb, buf, rc); 749 if (rc) 750 break; 751 } 752 753 if (console->pollfds[console->n_pollers + 1].revents) { 754 sd_bus_process(console->bus, NULL); 755 } 756 757 /* ... and then the pollers */ 758 rc = call_pollers(console, &tv); 759 if (rc) 760 break; 761 } 762 763 signal(SIGINT, sighandler_save); 764 sd_bus_unref(console->bus); 765 766 return rc ? -1 : 0; 767 } 768 static const struct option options[] = { 769 { "config", required_argument, 0, 'c'}, 770 { 0, 0, 0, 0}, 771 }; 772 773 int main(int argc, char **argv) 774 { 775 const char *config_filename = NULL; 776 const char *config_tty_kname = NULL; 777 struct console *console; 778 struct config *config; 779 int rc; 780 781 rc = -1; 782 783 for (;;) { 784 int c, idx; 785 786 c = getopt_long(argc, argv, "c:", options, &idx); 787 if (c == -1) 788 break; 789 790 switch (c) { 791 case 'c': 792 config_filename = optarg; 793 break; 794 case 'h': 795 case '?': 796 usage(argv[0]); 797 return EXIT_SUCCESS; 798 } 799 } 800 801 if (optind < argc) 802 config_tty_kname = argv[optind]; 803 804 console = malloc(sizeof(struct console)); 805 memset(console, 0, sizeof(*console)); 806 console->pollfds = calloc(MAX_INTERNAL_POLLFD, 807 sizeof(*console->pollfds)); 808 console->rb = ringbuffer_init(buffer_size); 809 810 config = config_init(config_filename); 811 if (!config) { 812 warnx("Can't read configuration, exiting."); 813 goto out_free; 814 } 815 816 if (!config_tty_kname) 817 config_tty_kname = config_get_value(config, "upstream-tty"); 818 819 if (!config_tty_kname) { 820 warnx("No TTY device specified"); 821 usage(argv[0]); 822 return EXIT_FAILURE; 823 } 824 825 console->tty_kname = config_tty_kname; 826 827 rc = tty_init(console, config); 828 if (rc) 829 goto out_config_fini; 830 831 dbus_init(console, config); 832 833 handlers_init(console, config); 834 835 rc = run_console(console); 836 837 handlers_fini(console); 838 839 out_config_fini: 840 config_fini(config); 841 842 out_free: 843 free(console->pollers); 844 free(console->pollfds); 845 free(console->tty_sysfs_devnode); 846 free(console->tty_dev); 847 free(console); 848 849 return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 850 } 851