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