1d831f960SJeremy Kerr /** 2d831f960SJeremy Kerr * Console server process for OpenBMC 3d831f960SJeremy Kerr * 4*9326d779SJeremy Kerr * Copyright © 2016 IBM Corporation 5*9326d779SJeremy Kerr * 6*9326d779SJeremy Kerr * Licensed under the Apache License, Version 2.0 (the "License"); 7*9326d779SJeremy Kerr * you may not use this file except in compliance with the License. 8*9326d779SJeremy Kerr * You may obtain a copy of the License at 9*9326d779SJeremy Kerr * 10*9326d779SJeremy Kerr * http://www.apache.org/licenses/LICENSE-2.0 11*9326d779SJeremy Kerr * 12*9326d779SJeremy Kerr * Unless required by applicable law or agreed to in writing, software 13*9326d779SJeremy Kerr * distributed under the License is distributed on an "AS IS" BASIS, 14*9326d779SJeremy Kerr * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15*9326d779SJeremy Kerr * See the License for the specific language governing permissions and 16*9326d779SJeremy Kerr * limitations under the License. 17d831f960SJeremy Kerr */ 18d831f960SJeremy Kerr 1917217845SJeremy Kerr #define _GNU_SOURCE 2017217845SJeremy Kerr 21329a35f5SJeremy Kerr #include <assert.h> 22769cee1aSJeremy Kerr #include <errno.h> 23769cee1aSJeremy Kerr #include <signal.h> 24d831f960SJeremy Kerr #include <stdint.h> 25d831f960SJeremy Kerr #include <stdbool.h> 26d831f960SJeremy Kerr #include <stdlib.h> 27d831f960SJeremy Kerr #include <stdio.h> 28d831f960SJeremy Kerr #include <fcntl.h> 29d831f960SJeremy Kerr #include <unistd.h> 30d831f960SJeremy Kerr #include <err.h> 31d831f960SJeremy Kerr #include <string.h> 32d831f960SJeremy Kerr #include <getopt.h> 3317217845SJeremy Kerr #include <limits.h> 34d831f960SJeremy Kerr 35d831f960SJeremy Kerr #include <sys/types.h> 36d831f960SJeremy Kerr #include <sys/poll.h> 37d831f960SJeremy Kerr 381a0e03b4SJeremy Kerr #include "console-server.h" 39d831f960SJeremy Kerr 401a0e03b4SJeremy Kerr struct console { 4117217845SJeremy Kerr const char *tty_kname; 4217217845SJeremy Kerr char *tty_sysfs_devnode; 4317217845SJeremy Kerr char *tty_dev; 44957818b4SJeremy Kerr int tty_sirq; 45957818b4SJeremy Kerr int tty_lpc_addr; 46d831f960SJeremy Kerr int tty_fd; 47329a35f5SJeremy Kerr 481a0e03b4SJeremy Kerr struct handler **handlers; 491a0e03b4SJeremy Kerr int n_handlers; 50329a35f5SJeremy Kerr 51329a35f5SJeremy Kerr struct poller **pollers; 52329a35f5SJeremy Kerr int n_pollers; 53329a35f5SJeremy Kerr 54329a35f5SJeremy Kerr struct pollfd *pollfds; 55d831f960SJeremy Kerr }; 56d831f960SJeremy Kerr 57329a35f5SJeremy Kerr struct poller { 58329a35f5SJeremy Kerr struct handler *handler; 59329a35f5SJeremy Kerr void *data; 60329a35f5SJeremy Kerr poller_fn_t fn; 61329a35f5SJeremy Kerr bool remove; 62329a35f5SJeremy Kerr }; 63329a35f5SJeremy Kerr 64329a35f5SJeremy Kerr /* we have one extra entry in the pollfds array for the VUART tty */ 65329a35f5SJeremy Kerr static const int n_internal_pollfds = 1; 66329a35f5SJeremy Kerr 67769cee1aSJeremy Kerr /* state shared with the signal handler */ 68769cee1aSJeremy Kerr static bool sigint; 69329a35f5SJeremy Kerr 70d831f960SJeremy Kerr static void usage(const char *progname) 71d831f960SJeremy Kerr { 72d831f960SJeremy Kerr fprintf(stderr, 73d831f960SJeremy Kerr "usage: %s [options]\n" 74d831f960SJeremy Kerr "\n" 75d831f960SJeremy Kerr "Options:\n" 76d66195c1SJeremy Kerr " --config <FILE> Use FILE for configuration\n" 77d831f960SJeremy Kerr "", 78d831f960SJeremy Kerr progname); 79d831f960SJeremy Kerr } 80d831f960SJeremy Kerr 8117217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 821a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 8317217845SJeremy Kerr { 8417217845SJeremy Kerr char *tty_class_device_link; 8517217845SJeremy Kerr char *tty_device_tty_dir; 8617217845SJeremy Kerr char *tty_device_reldir; 8717217845SJeremy Kerr int rc; 8817217845SJeremy Kerr 8917217845SJeremy Kerr rc = -1; 9017217845SJeremy Kerr tty_class_device_link = NULL; 9117217845SJeremy Kerr tty_device_tty_dir = NULL; 9217217845SJeremy Kerr tty_device_reldir = NULL; 9317217845SJeremy Kerr 9417217845SJeremy Kerr rc = asprintf(&tty_class_device_link, 951a0e03b4SJeremy Kerr "/sys/class/tty/%s", console->tty_kname); 9617217845SJeremy Kerr if (rc < 0) 9717217845SJeremy Kerr return -1; 9817217845SJeremy Kerr 9917217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 10017217845SJeremy Kerr if (rc < 0) { 1011a0e03b4SJeremy Kerr warn("Can't query sysfs for device %s", console->tty_kname); 10217217845SJeremy Kerr goto out_free; 10317217845SJeremy Kerr } 10417217845SJeremy Kerr 10517217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 10617217845SJeremy Kerr if (rc < 0) 10717217845SJeremy Kerr goto out_free; 10817217845SJeremy Kerr 1091a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1101a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 1111a0e03b4SJeremy Kerr warn("Can't find parent device for %s", console->tty_kname); 11217217845SJeremy Kerr 11317217845SJeremy Kerr 11417217845SJeremy Kerr /* todo: lookup from major/minor info in sysfs, in case udev has 11517217845SJeremy Kerr * renamed us */ 1161a0e03b4SJeremy Kerr rc = asprintf(&console->tty_dev, "/dev/%s", console->tty_kname); 11717217845SJeremy Kerr if (rc < 0) 11817217845SJeremy Kerr goto out_free; 11917217845SJeremy Kerr 12017217845SJeremy Kerr rc = 0; 12117217845SJeremy Kerr 12217217845SJeremy Kerr out_free: 12317217845SJeremy Kerr free(tty_class_device_link); 12417217845SJeremy Kerr free(tty_device_tty_dir); 12517217845SJeremy Kerr free(tty_device_reldir); 12617217845SJeremy Kerr return rc; 12717217845SJeremy Kerr } 12817217845SJeremy Kerr 1291a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 130957818b4SJeremy Kerr int value) 131957818b4SJeremy Kerr { 132957818b4SJeremy Kerr char *path; 133957818b4SJeremy Kerr FILE *fp; 134957818b4SJeremy Kerr int rc; 135957818b4SJeremy Kerr 1361a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 137957818b4SJeremy Kerr if (rc < 0) 138957818b4SJeremy Kerr return -1; 139957818b4SJeremy Kerr 140957818b4SJeremy Kerr fp = fopen(path, "w"); 141957818b4SJeremy Kerr if (!fp) { 142957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1431a0e03b4SJeremy Kerr name, console->tty_kname); 144957818b4SJeremy Kerr rc = -1; 145957818b4SJeremy Kerr goto out_free; 146957818b4SJeremy Kerr } 147957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 148957818b4SJeremy Kerr 149957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 150957818b4SJeremy Kerr if (rc < 0) 151957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1521a0e03b4SJeremy Kerr name, console->tty_kname); 153957818b4SJeremy Kerr fclose(fp); 154957818b4SJeremy Kerr 155957818b4SJeremy Kerr 156957818b4SJeremy Kerr 157957818b4SJeremy Kerr out_free: 158957818b4SJeremy Kerr free(path); 159957818b4SJeremy Kerr return rc; 160957818b4SJeremy Kerr } 161957818b4SJeremy Kerr 162d831f960SJeremy Kerr /** 163d831f960SJeremy Kerr * Open and initialise the serial device 164d831f960SJeremy Kerr */ 1651a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 166d831f960SJeremy Kerr { 1671a0e03b4SJeremy Kerr if (console->tty_sirq) 1681a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 1691a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 1701a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 1711a0e03b4SJeremy Kerr console->tty_lpc_addr); 1721a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "enabled", 1); 173957818b4SJeremy Kerr 1741a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 1751a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 1761a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 177d831f960SJeremy Kerr return -1; 178d831f960SJeremy Kerr } 179d831f960SJeremy Kerr 180d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 181d831f960SJeremy Kerr * we detect larger amounts of data 182d831f960SJeremy Kerr */ 1831a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 184d831f960SJeremy Kerr 185329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 186329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 187329a35f5SJeremy Kerr 188d831f960SJeremy Kerr return 0; 189d831f960SJeremy Kerr } 190d831f960SJeremy Kerr 191d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 192d66195c1SJeremy Kerr { 193d66195c1SJeremy Kerr const char *val; 194d66195c1SJeremy Kerr char *endp; 195d66195c1SJeremy Kerr int rc; 196d66195c1SJeremy Kerr 197d66195c1SJeremy Kerr console->tty_kname = config_get_value(config, "device"); 198d66195c1SJeremy Kerr 199d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 200d66195c1SJeremy Kerr if (val) { 201d66195c1SJeremy Kerr console->tty_lpc_addr = strtoul(val, &endp, 0); 202d66195c1SJeremy Kerr if (endp == optarg) { 203d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 204d66195c1SJeremy Kerr return -1; 205d66195c1SJeremy Kerr } 206d66195c1SJeremy Kerr } 207d66195c1SJeremy Kerr 208d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 209d66195c1SJeremy Kerr if (val) { 210d66195c1SJeremy Kerr console->tty_sirq = strtoul(val, &endp, 0); 211d66195c1SJeremy Kerr if (endp == optarg) 212d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 213d66195c1SJeremy Kerr } 214d66195c1SJeremy Kerr 215d66195c1SJeremy Kerr if (!console->tty_kname) { 216d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 217d66195c1SJeremy Kerr return -1; 218d66195c1SJeremy Kerr } 219d66195c1SJeremy Kerr 220d66195c1SJeremy Kerr rc = tty_find_device(console); 221d66195c1SJeremy Kerr if (rc) 222d66195c1SJeremy Kerr return rc; 223d66195c1SJeremy Kerr 224d66195c1SJeremy Kerr rc = tty_init_io(console); 225d66195c1SJeremy Kerr return rc; 226d66195c1SJeremy Kerr } 227d66195c1SJeremy Kerr 2281a0e03b4SJeremy Kerr 2291a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 230d831f960SJeremy Kerr { 2311a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 232d831f960SJeremy Kerr } 233d831f960SJeremy Kerr 234d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 235d831f960SJeremy Kerr { 2361a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 2371a0e03b4SJeremy Kerr struct handler *handler; 2381a0e03b4SJeremy Kerr int i; 239d831f960SJeremy Kerr 2401a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 2411a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 242d831f960SJeremy Kerr 2431a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 2441a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 245d831f960SJeremy Kerr 2461a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2471a0e03b4SJeremy Kerr handler = console->handlers[i]; 2481a0e03b4SJeremy Kerr 2491a0e03b4SJeremy Kerr printf(" %s\n", handler->name); 2501a0e03b4SJeremy Kerr 2511a0e03b4SJeremy Kerr if (handler->init) 252d47963e5SJeremy Kerr handler->init(handler, console, config); 253d831f960SJeremy Kerr } 254d831f960SJeremy Kerr } 255d831f960SJeremy Kerr 2561a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 257d831f960SJeremy Kerr { 2581a0e03b4SJeremy Kerr struct handler *handler; 2591a0e03b4SJeremy Kerr int i; 2601a0e03b4SJeremy Kerr 2611a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2621a0e03b4SJeremy Kerr handler = console->handlers[i]; 2631a0e03b4SJeremy Kerr if (handler->fini) 2641a0e03b4SJeremy Kerr handler->fini(handler); 2651a0e03b4SJeremy Kerr } 266d831f960SJeremy Kerr } 267d831f960SJeremy Kerr 2681a0e03b4SJeremy Kerr static int handlers_data_in(struct console *console, uint8_t *buf, size_t len) 269d831f960SJeremy Kerr { 2701a0e03b4SJeremy Kerr struct handler *handler; 2711a0e03b4SJeremy Kerr int i, rc, tmp; 272d831f960SJeremy Kerr 2731a0e03b4SJeremy Kerr rc = 0; 2741a0e03b4SJeremy Kerr 2751a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2761a0e03b4SJeremy Kerr handler = console->handlers[i]; 2771a0e03b4SJeremy Kerr 2781a0e03b4SJeremy Kerr if (!handler->data_in) 2791a0e03b4SJeremy Kerr continue; 2801a0e03b4SJeremy Kerr 2811a0e03b4SJeremy Kerr tmp = handler->data_in(handler, buf, len); 2821a0e03b4SJeremy Kerr if (tmp == HANDLER_EXIT) 2831a0e03b4SJeremy Kerr rc = 1; 284d831f960SJeremy Kerr } 285d831f960SJeremy Kerr 2861a0e03b4SJeremy Kerr return rc; 287329a35f5SJeremy Kerr 288d831f960SJeremy Kerr } 289d831f960SJeremy Kerr 290329a35f5SJeremy Kerr struct poller *console_register_poller(struct console *console, 291329a35f5SJeremy Kerr struct handler *handler, poller_fn_t poller_fn, 292329a35f5SJeremy Kerr int fd, int events, void *data) 293d831f960SJeremy Kerr { 294329a35f5SJeremy Kerr struct poller *poller; 295329a35f5SJeremy Kerr int n; 296329a35f5SJeremy Kerr 297329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 298329a35f5SJeremy Kerr poller->remove = false; 299329a35f5SJeremy Kerr poller->handler = handler; 300329a35f5SJeremy Kerr poller->fn = poller_fn; 301329a35f5SJeremy Kerr poller->data = data; 302329a35f5SJeremy Kerr 303329a35f5SJeremy Kerr /* add one to our pollers array */ 304329a35f5SJeremy Kerr n = console->n_pollers++; 305329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 306329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 307329a35f5SJeremy Kerr 308329a35f5SJeremy Kerr console->pollers[n] = poller; 309329a35f5SJeremy Kerr 310329a35f5SJeremy Kerr /* increase pollfds array too */ 311329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 312329a35f5SJeremy Kerr sizeof(*console->pollfds) * 313329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 314329a35f5SJeremy Kerr 315329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 316329a35f5SJeremy Kerr memcpy(&console->pollfds[n+n_internal_pollfds], 317329a35f5SJeremy Kerr &console->pollfds[n], 318329a35f5SJeremy Kerr sizeof(*console->pollfds) * n_internal_pollfds); 319329a35f5SJeremy Kerr 320329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 321329a35f5SJeremy Kerr console->pollfds[n].events = events; 322329a35f5SJeremy Kerr 323329a35f5SJeremy Kerr return poller; 324329a35f5SJeremy Kerr } 325329a35f5SJeremy Kerr 326329a35f5SJeremy Kerr void console_unregister_poller(struct console *console, 327329a35f5SJeremy Kerr struct poller *poller) 328329a35f5SJeremy Kerr { 329329a35f5SJeremy Kerr int i; 330329a35f5SJeremy Kerr 331329a35f5SJeremy Kerr /* find the entry in our pollers array */ 332329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 333329a35f5SJeremy Kerr if (console->pollers[i] == poller) 334329a35f5SJeremy Kerr break; 335329a35f5SJeremy Kerr 336329a35f5SJeremy Kerr assert(i < console->n_pollers); 337329a35f5SJeremy Kerr 338329a35f5SJeremy Kerr console->n_pollers--; 339329a35f5SJeremy Kerr 340329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 341329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 342329a35f5SJeremy Kerr sizeof(*console->pollers) 343329a35f5SJeremy Kerr * (console->n_pollers - i)); 344329a35f5SJeremy Kerr 345329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 346329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 347329a35f5SJeremy Kerr 348329a35f5SJeremy Kerr /* ... and the pollfds array */ 349329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 350329a35f5SJeremy Kerr sizeof(*console->pollfds) * 351329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers - i)); 352329a35f5SJeremy Kerr 353329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 354329a35f5SJeremy Kerr sizeof(*console->pollfds) * 355329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 356329a35f5SJeremy Kerr 357329a35f5SJeremy Kerr 358329a35f5SJeremy Kerr free(poller); 359329a35f5SJeremy Kerr } 360329a35f5SJeremy Kerr 361329a35f5SJeremy Kerr static int call_pollers(struct console *console) 362329a35f5SJeremy Kerr { 363329a35f5SJeremy Kerr struct poller *poller; 364329a35f5SJeremy Kerr struct pollfd *pollfd; 365329a35f5SJeremy Kerr enum poller_ret prc; 366329a35f5SJeremy Kerr int i, rc; 367d831f960SJeremy Kerr 3681a0e03b4SJeremy Kerr rc = 0; 3691a0e03b4SJeremy Kerr 370329a35f5SJeremy Kerr /* 371329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 372329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 373329a35f5SJeremy Kerr */ 374329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 375329a35f5SJeremy Kerr poller = console->pollers[i]; 376329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 3771a0e03b4SJeremy Kerr 378329a35f5SJeremy Kerr if (!pollfd->revents) 3791a0e03b4SJeremy Kerr continue; 3801a0e03b4SJeremy Kerr 381329a35f5SJeremy Kerr prc = poller->fn(poller->handler, pollfd->revents, 382329a35f5SJeremy Kerr poller->data); 383329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 384329a35f5SJeremy Kerr rc = -1; 385329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 386329a35f5SJeremy Kerr poller->remove = true; 387329a35f5SJeremy Kerr } 388329a35f5SJeremy Kerr 389329a35f5SJeremy Kerr /** 390329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 391329a35f5SJeremy Kerr * the array will have changed 392329a35f5SJeremy Kerr */ 393329a35f5SJeremy Kerr for (;;) { 394329a35f5SJeremy Kerr bool removed = false; 395329a35f5SJeremy Kerr 396329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 397329a35f5SJeremy Kerr poller = console->pollers[i]; 398329a35f5SJeremy Kerr if (poller->remove) { 399329a35f5SJeremy Kerr console_unregister_poller(console, poller); 400329a35f5SJeremy Kerr removed = true; 401329a35f5SJeremy Kerr break; 402329a35f5SJeremy Kerr } 403329a35f5SJeremy Kerr } 404329a35f5SJeremy Kerr if (!removed) 405329a35f5SJeremy Kerr break; 4061a0e03b4SJeremy Kerr } 4071a0e03b4SJeremy Kerr 4081a0e03b4SJeremy Kerr return rc; 4091a0e03b4SJeremy Kerr } 4101a0e03b4SJeremy Kerr 411769cee1aSJeremy Kerr static void sighandler(int signal) 412769cee1aSJeremy Kerr { 413769cee1aSJeremy Kerr if (signal == SIGINT) 414769cee1aSJeremy Kerr sigint = true; 415769cee1aSJeremy Kerr } 416769cee1aSJeremy Kerr 4171a0e03b4SJeremy Kerr int run_console(struct console *console) 4181a0e03b4SJeremy Kerr { 419769cee1aSJeremy Kerr sighandler_t sighandler_save; 420329a35f5SJeremy Kerr int rc; 421d831f960SJeremy Kerr 422769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 423769cee1aSJeremy Kerr 424769cee1aSJeremy Kerr rc = 0; 425769cee1aSJeremy Kerr 426d831f960SJeremy Kerr for (;;) { 427d831f960SJeremy Kerr uint8_t buf[4096]; 428d831f960SJeremy Kerr 429769cee1aSJeremy Kerr if (sigint) { 430769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 431769cee1aSJeremy Kerr break; 432769cee1aSJeremy Kerr } 433769cee1aSJeremy Kerr 434329a35f5SJeremy Kerr rc = poll(console->pollfds, 435329a35f5SJeremy Kerr console->n_pollers + n_internal_pollfds, -1); 436d831f960SJeremy Kerr if (rc < 0) { 437769cee1aSJeremy Kerr if (errno == EINTR) { 438769cee1aSJeremy Kerr continue; 439769cee1aSJeremy Kerr } else { 440d831f960SJeremy Kerr warn("poll error"); 441769cee1aSJeremy Kerr break; 442769cee1aSJeremy Kerr } 443d831f960SJeremy Kerr } 444d831f960SJeremy Kerr 445329a35f5SJeremy Kerr /* process internal fd first */ 446329a35f5SJeremy Kerr BUILD_ASSERT(n_internal_pollfds == 1); 447329a35f5SJeremy Kerr 448329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 4491a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 450d831f960SJeremy Kerr if (rc <= 0) { 451d831f960SJeremy Kerr warn("Error reading from tty device"); 452769cee1aSJeremy Kerr rc = -1; 453769cee1aSJeremy Kerr break; 454d831f960SJeremy Kerr } 4551a0e03b4SJeremy Kerr rc = handlers_data_in(console, buf, rc); 4561a0e03b4SJeremy Kerr if (rc) 457769cee1aSJeremy Kerr break; 458d831f960SJeremy Kerr } 459d831f960SJeremy Kerr 460329a35f5SJeremy Kerr /* ... and then the pollers */ 461329a35f5SJeremy Kerr rc = call_pollers(console); 4621a0e03b4SJeremy Kerr if (rc) 463769cee1aSJeremy Kerr break; 4641a0e03b4SJeremy Kerr } 465769cee1aSJeremy Kerr 466769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 467769cee1aSJeremy Kerr 468769cee1aSJeremy Kerr return rc ? -1 : 0; 4691a0e03b4SJeremy Kerr } 470d831f960SJeremy Kerr static const struct option options[] = { 471d66195c1SJeremy Kerr { "config", required_argument, 0, 'c'}, 472e3f94547SJeremy Kerr { 0 }, 473d831f960SJeremy Kerr }; 474d831f960SJeremy Kerr 475d831f960SJeremy Kerr int main(int argc, char **argv) 476d831f960SJeremy Kerr { 477d66195c1SJeremy Kerr const char *config_filename = NULL; 4781a0e03b4SJeremy Kerr struct console *console; 479d66195c1SJeremy Kerr struct config *config; 480d66195c1SJeremy Kerr int rc; 481d831f960SJeremy Kerr 482957818b4SJeremy Kerr rc = -1; 483d831f960SJeremy Kerr 484d831f960SJeremy Kerr for (;;) { 485d831f960SJeremy Kerr int c, idx; 486d831f960SJeremy Kerr 487d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 488d831f960SJeremy Kerr if (c == -1) 489d831f960SJeremy Kerr break; 490d831f960SJeremy Kerr 491d831f960SJeremy Kerr switch (c) { 492d66195c1SJeremy Kerr case 'c': 493d66195c1SJeremy Kerr config_filename = optarg; 494d831f960SJeremy Kerr break; 495d831f960SJeremy Kerr case 'h': 496d831f960SJeremy Kerr case '?': 497d831f960SJeremy Kerr usage(argv[0]); 498d66195c1SJeremy Kerr return EXIT_SUCCESS; 499d831f960SJeremy Kerr } 500d831f960SJeremy Kerr } 501d831f960SJeremy Kerr 502d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 503d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 504329a35f5SJeremy Kerr console->pollfds = calloc(n_internal_pollfds, 505329a35f5SJeremy Kerr sizeof(*console->pollfds)); 506329a35f5SJeremy Kerr 507d66195c1SJeremy Kerr config = config_init(config_filename); 508d66195c1SJeremy Kerr if (!config) { 509d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 510d66195c1SJeremy Kerr goto out_free; 511d831f960SJeremy Kerr } 512d831f960SJeremy Kerr 513d66195c1SJeremy Kerr rc = tty_init(console, config); 51417217845SJeremy Kerr if (rc) 515d66195c1SJeremy Kerr goto out_config_fini; 516d831f960SJeremy Kerr 517d47963e5SJeremy Kerr handlers_init(console, config); 518d831f960SJeremy Kerr 5191a0e03b4SJeremy Kerr rc = run_console(console); 520d831f960SJeremy Kerr 5211a0e03b4SJeremy Kerr handlers_fini(console); 522d831f960SJeremy Kerr 523d66195c1SJeremy Kerr out_config_fini: 524d66195c1SJeremy Kerr config_fini(config); 525d66195c1SJeremy Kerr 526957818b4SJeremy Kerr out_free: 52789ea8198SJeremy Kerr free(console->pollers); 52889ea8198SJeremy Kerr free(console->pollfds); 5291a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 5301a0e03b4SJeremy Kerr free(console->tty_dev); 5311a0e03b4SJeremy Kerr free(console); 532d831f960SJeremy Kerr 533d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 534d831f960SJeremy Kerr } 535