1d831f960SJeremy Kerr /** 2d831f960SJeremy Kerr * Console server process for OpenBMC 3d831f960SJeremy Kerr * 4d831f960SJeremy Kerr * Copyright © 2016 IBM Corporation <jk@ozlabs.org> 5d831f960SJeremy Kerr */ 6d831f960SJeremy Kerr 717217845SJeremy Kerr #define _GNU_SOURCE 817217845SJeremy Kerr 9329a35f5SJeremy Kerr #include <assert.h> 10769cee1aSJeremy Kerr #include <errno.h> 11769cee1aSJeremy Kerr #include <signal.h> 12d831f960SJeremy Kerr #include <stdint.h> 13d831f960SJeremy Kerr #include <stdbool.h> 14d831f960SJeremy Kerr #include <stdlib.h> 15d831f960SJeremy Kerr #include <stdio.h> 16d831f960SJeremy Kerr #include <fcntl.h> 17d831f960SJeremy Kerr #include <unistd.h> 18d831f960SJeremy Kerr #include <err.h> 19d831f960SJeremy Kerr #include <string.h> 20d831f960SJeremy Kerr #include <getopt.h> 2117217845SJeremy Kerr #include <limits.h> 22d831f960SJeremy Kerr 23d831f960SJeremy Kerr #include <sys/types.h> 24d831f960SJeremy Kerr #include <sys/poll.h> 25d831f960SJeremy Kerr 261a0e03b4SJeremy Kerr #include "console-server.h" 27d831f960SJeremy Kerr 281a0e03b4SJeremy Kerr struct console { 2917217845SJeremy Kerr const char *tty_kname; 3017217845SJeremy Kerr char *tty_sysfs_devnode; 3117217845SJeremy Kerr char *tty_dev; 32957818b4SJeremy Kerr int tty_sirq; 33957818b4SJeremy Kerr int tty_lpc_addr; 34d831f960SJeremy Kerr int tty_fd; 35329a35f5SJeremy Kerr 361a0e03b4SJeremy Kerr struct handler **handlers; 371a0e03b4SJeremy Kerr int n_handlers; 38329a35f5SJeremy Kerr 39329a35f5SJeremy Kerr struct poller **pollers; 40329a35f5SJeremy Kerr int n_pollers; 41329a35f5SJeremy Kerr 42329a35f5SJeremy Kerr struct pollfd *pollfds; 43d831f960SJeremy Kerr }; 44d831f960SJeremy Kerr 45329a35f5SJeremy Kerr struct poller { 46329a35f5SJeremy Kerr struct handler *handler; 47329a35f5SJeremy Kerr void *data; 48329a35f5SJeremy Kerr poller_fn_t fn; 49329a35f5SJeremy Kerr bool remove; 50329a35f5SJeremy Kerr }; 51329a35f5SJeremy Kerr 52329a35f5SJeremy Kerr /* we have one extra entry in the pollfds array for the VUART tty */ 53329a35f5SJeremy Kerr static const int n_internal_pollfds = 1; 54329a35f5SJeremy Kerr 55769cee1aSJeremy Kerr /* state shared with the signal handler */ 56769cee1aSJeremy Kerr static bool sigint; 57329a35f5SJeremy Kerr 58d831f960SJeremy Kerr static void usage(const char *progname) 59d831f960SJeremy Kerr { 60d831f960SJeremy Kerr fprintf(stderr, 61d831f960SJeremy Kerr "usage: %s [options]\n" 62d831f960SJeremy Kerr "\n" 63d831f960SJeremy Kerr "Options:\n" 64*d66195c1SJeremy Kerr " --config <FILE> Use FILE for configuration\n" 65d831f960SJeremy Kerr "", 66d831f960SJeremy Kerr progname); 67d831f960SJeremy Kerr } 68d831f960SJeremy Kerr 6917217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 701a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 7117217845SJeremy Kerr { 7217217845SJeremy Kerr char *tty_class_device_link; 7317217845SJeremy Kerr char *tty_device_tty_dir; 7417217845SJeremy Kerr char *tty_device_reldir; 7517217845SJeremy Kerr int rc; 7617217845SJeremy Kerr 7717217845SJeremy Kerr rc = -1; 7817217845SJeremy Kerr tty_class_device_link = NULL; 7917217845SJeremy Kerr tty_device_tty_dir = NULL; 8017217845SJeremy Kerr tty_device_reldir = NULL; 8117217845SJeremy Kerr 8217217845SJeremy Kerr rc = asprintf(&tty_class_device_link, 831a0e03b4SJeremy Kerr "/sys/class/tty/%s", console->tty_kname); 8417217845SJeremy Kerr if (rc < 0) 8517217845SJeremy Kerr return -1; 8617217845SJeremy Kerr 8717217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 8817217845SJeremy Kerr if (rc < 0) { 891a0e03b4SJeremy Kerr warn("Can't query sysfs for device %s", console->tty_kname); 9017217845SJeremy Kerr goto out_free; 9117217845SJeremy Kerr } 9217217845SJeremy Kerr 9317217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 9417217845SJeremy Kerr if (rc < 0) 9517217845SJeremy Kerr goto out_free; 9617217845SJeremy Kerr 971a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 981a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 991a0e03b4SJeremy Kerr warn("Can't find parent device for %s", console->tty_kname); 10017217845SJeremy Kerr 10117217845SJeremy Kerr 10217217845SJeremy Kerr /* todo: lookup from major/minor info in sysfs, in case udev has 10317217845SJeremy Kerr * renamed us */ 1041a0e03b4SJeremy Kerr rc = asprintf(&console->tty_dev, "/dev/%s", console->tty_kname); 10517217845SJeremy Kerr if (rc < 0) 10617217845SJeremy Kerr goto out_free; 10717217845SJeremy Kerr 10817217845SJeremy Kerr rc = 0; 10917217845SJeremy Kerr 11017217845SJeremy Kerr out_free: 11117217845SJeremy Kerr free(tty_class_device_link); 11217217845SJeremy Kerr free(tty_device_tty_dir); 11317217845SJeremy Kerr free(tty_device_reldir); 11417217845SJeremy Kerr return rc; 11517217845SJeremy Kerr } 11617217845SJeremy Kerr 1171a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 118957818b4SJeremy Kerr int value) 119957818b4SJeremy Kerr { 120957818b4SJeremy Kerr char *path; 121957818b4SJeremy Kerr FILE *fp; 122957818b4SJeremy Kerr int rc; 123957818b4SJeremy Kerr 1241a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 125957818b4SJeremy Kerr if (rc < 0) 126957818b4SJeremy Kerr return -1; 127957818b4SJeremy Kerr 128957818b4SJeremy Kerr fp = fopen(path, "w"); 129957818b4SJeremy Kerr if (!fp) { 130957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1311a0e03b4SJeremy Kerr name, console->tty_kname); 132957818b4SJeremy Kerr rc = -1; 133957818b4SJeremy Kerr goto out_free; 134957818b4SJeremy Kerr } 135957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 136957818b4SJeremy Kerr 137957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 138957818b4SJeremy Kerr if (rc < 0) 139957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1401a0e03b4SJeremy Kerr name, console->tty_kname); 141957818b4SJeremy Kerr fclose(fp); 142957818b4SJeremy Kerr 143957818b4SJeremy Kerr 144957818b4SJeremy Kerr 145957818b4SJeremy Kerr out_free: 146957818b4SJeremy Kerr free(path); 147957818b4SJeremy Kerr return rc; 148957818b4SJeremy Kerr } 149957818b4SJeremy Kerr 150d831f960SJeremy Kerr /** 151d831f960SJeremy Kerr * Open and initialise the serial device 152d831f960SJeremy Kerr */ 1531a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 154d831f960SJeremy Kerr { 1551a0e03b4SJeremy Kerr if (console->tty_sirq) 1561a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 1571a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 1581a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 1591a0e03b4SJeremy Kerr console->tty_lpc_addr); 1601a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "enabled", 1); 161957818b4SJeremy Kerr 1621a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 1631a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 1641a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 165d831f960SJeremy Kerr return -1; 166d831f960SJeremy Kerr } 167d831f960SJeremy Kerr 168d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 169d831f960SJeremy Kerr * we detect larger amounts of data 170d831f960SJeremy Kerr */ 1711a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 172d831f960SJeremy Kerr 173329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 174329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 175329a35f5SJeremy Kerr 176d831f960SJeremy Kerr return 0; 177d831f960SJeremy Kerr } 178d831f960SJeremy Kerr 179*d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 180*d66195c1SJeremy Kerr { 181*d66195c1SJeremy Kerr const char *val; 182*d66195c1SJeremy Kerr char *endp; 183*d66195c1SJeremy Kerr int rc; 184*d66195c1SJeremy Kerr 185*d66195c1SJeremy Kerr console->tty_kname = config_get_value(config, "device"); 186*d66195c1SJeremy Kerr 187*d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 188*d66195c1SJeremy Kerr if (val) { 189*d66195c1SJeremy Kerr console->tty_lpc_addr = strtoul(val, &endp, 0); 190*d66195c1SJeremy Kerr if (endp == optarg) { 191*d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 192*d66195c1SJeremy Kerr return -1; 193*d66195c1SJeremy Kerr } 194*d66195c1SJeremy Kerr } 195*d66195c1SJeremy Kerr 196*d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 197*d66195c1SJeremy Kerr if (val) { 198*d66195c1SJeremy Kerr console->tty_sirq = strtoul(val, &endp, 0); 199*d66195c1SJeremy Kerr if (endp == optarg) 200*d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 201*d66195c1SJeremy Kerr } 202*d66195c1SJeremy Kerr 203*d66195c1SJeremy Kerr if (!console->tty_kname) { 204*d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 205*d66195c1SJeremy Kerr return -1; 206*d66195c1SJeremy Kerr } 207*d66195c1SJeremy Kerr 208*d66195c1SJeremy Kerr rc = tty_find_device(console); 209*d66195c1SJeremy Kerr if (rc) 210*d66195c1SJeremy Kerr return rc; 211*d66195c1SJeremy Kerr 212*d66195c1SJeremy Kerr rc = tty_init_io(console); 213*d66195c1SJeremy Kerr return rc; 214*d66195c1SJeremy Kerr } 215*d66195c1SJeremy Kerr 2161a0e03b4SJeremy Kerr 2171a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 218d831f960SJeremy Kerr { 2191a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 220d831f960SJeremy Kerr } 221d831f960SJeremy Kerr 2221a0e03b4SJeremy Kerr static void handlers_init(struct console *console) 223d831f960SJeremy Kerr { 2241a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 2251a0e03b4SJeremy Kerr struct handler *handler; 2261a0e03b4SJeremy Kerr int i; 227d831f960SJeremy Kerr 2281a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 2291a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 230d831f960SJeremy Kerr 2311a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 2321a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 233d831f960SJeremy Kerr 2341a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2351a0e03b4SJeremy Kerr handler = console->handlers[i]; 2361a0e03b4SJeremy Kerr 2371a0e03b4SJeremy Kerr printf(" %s\n", handler->name); 2381a0e03b4SJeremy Kerr 2391a0e03b4SJeremy Kerr if (handler->init) 2401a0e03b4SJeremy Kerr handler->init(handler, console); 241d831f960SJeremy Kerr } 242d831f960SJeremy Kerr } 243d831f960SJeremy Kerr 2441a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 245d831f960SJeremy Kerr { 2461a0e03b4SJeremy Kerr struct handler *handler; 2471a0e03b4SJeremy Kerr int i; 2481a0e03b4SJeremy Kerr 2491a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2501a0e03b4SJeremy Kerr handler = console->handlers[i]; 2511a0e03b4SJeremy Kerr if (handler->fini) 2521a0e03b4SJeremy Kerr handler->fini(handler); 2531a0e03b4SJeremy Kerr } 254d831f960SJeremy Kerr } 255d831f960SJeremy Kerr 2561a0e03b4SJeremy Kerr static int handlers_data_in(struct console *console, uint8_t *buf, size_t len) 257d831f960SJeremy Kerr { 2581a0e03b4SJeremy Kerr struct handler *handler; 2591a0e03b4SJeremy Kerr int i, rc, tmp; 260d831f960SJeremy Kerr 2611a0e03b4SJeremy Kerr rc = 0; 2621a0e03b4SJeremy Kerr 2631a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2641a0e03b4SJeremy Kerr handler = console->handlers[i]; 2651a0e03b4SJeremy Kerr 2661a0e03b4SJeremy Kerr if (!handler->data_in) 2671a0e03b4SJeremy Kerr continue; 2681a0e03b4SJeremy Kerr 2691a0e03b4SJeremy Kerr tmp = handler->data_in(handler, buf, len); 2701a0e03b4SJeremy Kerr if (tmp == HANDLER_EXIT) 2711a0e03b4SJeremy Kerr rc = 1; 272d831f960SJeremy Kerr } 273d831f960SJeremy Kerr 2741a0e03b4SJeremy Kerr return rc; 275329a35f5SJeremy Kerr 276d831f960SJeremy Kerr } 277d831f960SJeremy Kerr 278329a35f5SJeremy Kerr struct poller *console_register_poller(struct console *console, 279329a35f5SJeremy Kerr struct handler *handler, poller_fn_t poller_fn, 280329a35f5SJeremy Kerr int fd, int events, void *data) 281d831f960SJeremy Kerr { 282329a35f5SJeremy Kerr struct poller *poller; 283329a35f5SJeremy Kerr int n; 284329a35f5SJeremy Kerr 285329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 286329a35f5SJeremy Kerr poller->remove = false; 287329a35f5SJeremy Kerr poller->handler = handler; 288329a35f5SJeremy Kerr poller->fn = poller_fn; 289329a35f5SJeremy Kerr poller->data = data; 290329a35f5SJeremy Kerr 291329a35f5SJeremy Kerr /* add one to our pollers array */ 292329a35f5SJeremy Kerr n = console->n_pollers++; 293329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 294329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 295329a35f5SJeremy Kerr 296329a35f5SJeremy Kerr console->pollers[n] = poller; 297329a35f5SJeremy Kerr 298329a35f5SJeremy Kerr /* increase pollfds array too */ 299329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 300329a35f5SJeremy Kerr sizeof(*console->pollfds) * 301329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 302329a35f5SJeremy Kerr 303329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 304329a35f5SJeremy Kerr memcpy(&console->pollfds[n+n_internal_pollfds], 305329a35f5SJeremy Kerr &console->pollfds[n], 306329a35f5SJeremy Kerr sizeof(*console->pollfds) * n_internal_pollfds); 307329a35f5SJeremy Kerr 308329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 309329a35f5SJeremy Kerr console->pollfds[n].events = events; 310329a35f5SJeremy Kerr 311329a35f5SJeremy Kerr return poller; 312329a35f5SJeremy Kerr } 313329a35f5SJeremy Kerr 314329a35f5SJeremy Kerr void console_unregister_poller(struct console *console, 315329a35f5SJeremy Kerr struct poller *poller) 316329a35f5SJeremy Kerr { 317329a35f5SJeremy Kerr int i; 318329a35f5SJeremy Kerr 319329a35f5SJeremy Kerr /* find the entry in our pollers array */ 320329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 321329a35f5SJeremy Kerr if (console->pollers[i] == poller) 322329a35f5SJeremy Kerr break; 323329a35f5SJeremy Kerr 324329a35f5SJeremy Kerr assert(i < console->n_pollers); 325329a35f5SJeremy Kerr 326329a35f5SJeremy Kerr console->n_pollers--; 327329a35f5SJeremy Kerr 328329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 329329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 330329a35f5SJeremy Kerr sizeof(*console->pollers) 331329a35f5SJeremy Kerr * (console->n_pollers - i)); 332329a35f5SJeremy Kerr 333329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 334329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 335329a35f5SJeremy Kerr 336329a35f5SJeremy Kerr /* ... and the pollfds array */ 337329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 338329a35f5SJeremy Kerr sizeof(*console->pollfds) * 339329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers - i)); 340329a35f5SJeremy Kerr 341329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 342329a35f5SJeremy Kerr sizeof(*console->pollfds) * 343329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 344329a35f5SJeremy Kerr 345329a35f5SJeremy Kerr 346329a35f5SJeremy Kerr free(poller); 347329a35f5SJeremy Kerr } 348329a35f5SJeremy Kerr 349329a35f5SJeremy Kerr static int call_pollers(struct console *console) 350329a35f5SJeremy Kerr { 351329a35f5SJeremy Kerr struct poller *poller; 352329a35f5SJeremy Kerr struct pollfd *pollfd; 353329a35f5SJeremy Kerr enum poller_ret prc; 354329a35f5SJeremy Kerr int i, rc; 355d831f960SJeremy Kerr 3561a0e03b4SJeremy Kerr rc = 0; 3571a0e03b4SJeremy Kerr 358329a35f5SJeremy Kerr /* 359329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 360329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 361329a35f5SJeremy Kerr */ 362329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 363329a35f5SJeremy Kerr poller = console->pollers[i]; 364329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 3651a0e03b4SJeremy Kerr 366329a35f5SJeremy Kerr if (!pollfd->revents) 3671a0e03b4SJeremy Kerr continue; 3681a0e03b4SJeremy Kerr 369329a35f5SJeremy Kerr prc = poller->fn(poller->handler, pollfd->revents, 370329a35f5SJeremy Kerr poller->data); 371329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 372329a35f5SJeremy Kerr rc = -1; 373329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 374329a35f5SJeremy Kerr poller->remove = true; 375329a35f5SJeremy Kerr } 376329a35f5SJeremy Kerr 377329a35f5SJeremy Kerr /** 378329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 379329a35f5SJeremy Kerr * the array will have changed 380329a35f5SJeremy Kerr */ 381329a35f5SJeremy Kerr for (;;) { 382329a35f5SJeremy Kerr bool removed = false; 383329a35f5SJeremy Kerr 384329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 385329a35f5SJeremy Kerr poller = console->pollers[i]; 386329a35f5SJeremy Kerr if (poller->remove) { 387329a35f5SJeremy Kerr console_unregister_poller(console, poller); 388329a35f5SJeremy Kerr removed = true; 389329a35f5SJeremy Kerr break; 390329a35f5SJeremy Kerr } 391329a35f5SJeremy Kerr } 392329a35f5SJeremy Kerr if (!removed) 393329a35f5SJeremy Kerr break; 3941a0e03b4SJeremy Kerr } 3951a0e03b4SJeremy Kerr 3961a0e03b4SJeremy Kerr return rc; 3971a0e03b4SJeremy Kerr } 3981a0e03b4SJeremy Kerr 399769cee1aSJeremy Kerr static void sighandler(int signal) 400769cee1aSJeremy Kerr { 401769cee1aSJeremy Kerr if (signal == SIGINT) 402769cee1aSJeremy Kerr sigint = true; 403769cee1aSJeremy Kerr } 404769cee1aSJeremy Kerr 4051a0e03b4SJeremy Kerr int run_console(struct console *console) 4061a0e03b4SJeremy Kerr { 407769cee1aSJeremy Kerr sighandler_t sighandler_save; 408329a35f5SJeremy Kerr int rc; 409d831f960SJeremy Kerr 410769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 411769cee1aSJeremy Kerr 412769cee1aSJeremy Kerr rc = 0; 413769cee1aSJeremy Kerr 414d831f960SJeremy Kerr for (;;) { 415d831f960SJeremy Kerr uint8_t buf[4096]; 416d831f960SJeremy Kerr 417769cee1aSJeremy Kerr if (sigint) { 418769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 419769cee1aSJeremy Kerr break; 420769cee1aSJeremy Kerr } 421769cee1aSJeremy Kerr 422329a35f5SJeremy Kerr rc = poll(console->pollfds, 423329a35f5SJeremy Kerr console->n_pollers + n_internal_pollfds, -1); 424d831f960SJeremy Kerr if (rc < 0) { 425769cee1aSJeremy Kerr if (errno == EINTR) { 426769cee1aSJeremy Kerr continue; 427769cee1aSJeremy Kerr } else { 428d831f960SJeremy Kerr warn("poll error"); 429769cee1aSJeremy Kerr break; 430769cee1aSJeremy Kerr } 431d831f960SJeremy Kerr } 432d831f960SJeremy Kerr 433329a35f5SJeremy Kerr /* process internal fd first */ 434329a35f5SJeremy Kerr BUILD_ASSERT(n_internal_pollfds == 1); 435329a35f5SJeremy Kerr 436329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 4371a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 438d831f960SJeremy Kerr if (rc <= 0) { 439d831f960SJeremy Kerr warn("Error reading from tty device"); 440769cee1aSJeremy Kerr rc = -1; 441769cee1aSJeremy Kerr break; 442d831f960SJeremy Kerr } 4431a0e03b4SJeremy Kerr rc = handlers_data_in(console, buf, rc); 4441a0e03b4SJeremy Kerr if (rc) 445769cee1aSJeremy Kerr break; 446d831f960SJeremy Kerr } 447d831f960SJeremy Kerr 448329a35f5SJeremy Kerr /* ... and then the pollers */ 449329a35f5SJeremy Kerr rc = call_pollers(console); 4501a0e03b4SJeremy Kerr if (rc) 451769cee1aSJeremy Kerr break; 4521a0e03b4SJeremy Kerr } 453769cee1aSJeremy Kerr 454769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 455769cee1aSJeremy Kerr 456769cee1aSJeremy Kerr return rc ? -1 : 0; 4571a0e03b4SJeremy Kerr } 458d831f960SJeremy Kerr static const struct option options[] = { 459*d66195c1SJeremy Kerr { "config", required_argument, 0, 'c'}, 460d831f960SJeremy Kerr { }, 461d831f960SJeremy Kerr }; 462d831f960SJeremy Kerr 463d831f960SJeremy Kerr int main(int argc, char **argv) 464d831f960SJeremy Kerr { 465*d66195c1SJeremy Kerr const char *config_filename = NULL; 4661a0e03b4SJeremy Kerr struct console *console; 467*d66195c1SJeremy Kerr struct config *config; 468*d66195c1SJeremy Kerr int rc; 469d831f960SJeremy Kerr 470957818b4SJeremy Kerr rc = -1; 471d831f960SJeremy Kerr 472d831f960SJeremy Kerr for (;;) { 473d831f960SJeremy Kerr int c, idx; 474d831f960SJeremy Kerr 475*d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 476d831f960SJeremy Kerr if (c == -1) 477d831f960SJeremy Kerr break; 478d831f960SJeremy Kerr 479d831f960SJeremy Kerr switch (c) { 480*d66195c1SJeremy Kerr case 'c': 481*d66195c1SJeremy Kerr config_filename = optarg; 482d831f960SJeremy Kerr break; 483d831f960SJeremy Kerr case 'h': 484d831f960SJeremy Kerr case '?': 485d831f960SJeremy Kerr usage(argv[0]); 486*d66195c1SJeremy Kerr return EXIT_SUCCESS; 487d831f960SJeremy Kerr } 488d831f960SJeremy Kerr } 489d831f960SJeremy Kerr 490*d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 491*d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 492329a35f5SJeremy Kerr console->pollfds = calloc(n_internal_pollfds, 493329a35f5SJeremy Kerr sizeof(*console->pollfds)); 494329a35f5SJeremy Kerr 495*d66195c1SJeremy Kerr config = config_init(config_filename); 496*d66195c1SJeremy Kerr if (!config) { 497*d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 498*d66195c1SJeremy Kerr goto out_free; 499d831f960SJeremy Kerr } 500d831f960SJeremy Kerr 501*d66195c1SJeremy Kerr rc = tty_init(console, config); 50217217845SJeremy Kerr if (rc) 503*d66195c1SJeremy Kerr goto out_config_fini; 504d831f960SJeremy Kerr 5051a0e03b4SJeremy Kerr handlers_init(console); 506d831f960SJeremy Kerr 5071a0e03b4SJeremy Kerr rc = run_console(console); 508d831f960SJeremy Kerr 5091a0e03b4SJeremy Kerr handlers_fini(console); 510d831f960SJeremy Kerr 511*d66195c1SJeremy Kerr out_config_fini: 512*d66195c1SJeremy Kerr config_fini(config); 513*d66195c1SJeremy Kerr 514957818b4SJeremy Kerr out_free: 51589ea8198SJeremy Kerr free(console->pollers); 51689ea8198SJeremy Kerr free(console->pollfds); 5171a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 5181a0e03b4SJeremy Kerr free(console->tty_dev); 5191a0e03b4SJeremy Kerr free(console); 520d831f960SJeremy Kerr 521d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 522d831f960SJeremy Kerr } 523