1d831f960SJeremy Kerr /** 2d831f960SJeremy Kerr * Console server process for OpenBMC 3d831f960SJeremy Kerr * 49326d779SJeremy Kerr * Copyright © 2016 IBM Corporation 59326d779SJeremy Kerr * 69326d779SJeremy Kerr * Licensed under the Apache License, Version 2.0 (the "License"); 79326d779SJeremy Kerr * you may not use this file except in compliance with the License. 89326d779SJeremy Kerr * You may obtain a copy of the License at 99326d779SJeremy Kerr * 109326d779SJeremy Kerr * http://www.apache.org/licenses/LICENSE-2.0 119326d779SJeremy Kerr * 129326d779SJeremy Kerr * Unless required by applicable law or agreed to in writing, software 139326d779SJeremy Kerr * distributed under the License is distributed on an "AS IS" BASIS, 149326d779SJeremy Kerr * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 159326d779SJeremy Kerr * See the License for the specific language governing permissions and 169326d779SJeremy 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> 3454e9569dSJeremy Kerr #include <termios.h> 35d831f960SJeremy Kerr 36d831f960SJeremy Kerr #include <sys/types.h> 3787e344cdSJoel Stanley #include <poll.h> 38d831f960SJeremy Kerr 391a0e03b4SJeremy Kerr #include "console-server.h" 40d831f960SJeremy Kerr 411a0e03b4SJeremy Kerr struct console { 4217217845SJeremy Kerr const char *tty_kname; 4317217845SJeremy Kerr char *tty_sysfs_devnode; 4417217845SJeremy Kerr char *tty_dev; 45957818b4SJeremy Kerr int tty_sirq; 46957818b4SJeremy Kerr int tty_lpc_addr; 47d831f960SJeremy Kerr int tty_fd; 48329a35f5SJeremy Kerr 49*f733c85aSJeremy Kerr struct ringbuffer *rb; 50*f733c85aSJeremy Kerr 511a0e03b4SJeremy Kerr struct handler **handlers; 521a0e03b4SJeremy Kerr int n_handlers; 53329a35f5SJeremy Kerr 54329a35f5SJeremy Kerr struct poller **pollers; 55329a35f5SJeremy Kerr int n_pollers; 56329a35f5SJeremy Kerr 57329a35f5SJeremy Kerr struct pollfd *pollfds; 58d831f960SJeremy Kerr }; 59d831f960SJeremy Kerr 60329a35f5SJeremy Kerr struct poller { 61329a35f5SJeremy Kerr struct handler *handler; 62329a35f5SJeremy Kerr void *data; 63329a35f5SJeremy Kerr poller_fn_t fn; 64329a35f5SJeremy Kerr bool remove; 65329a35f5SJeremy Kerr }; 66329a35f5SJeremy Kerr 67329a35f5SJeremy Kerr /* we have one extra entry in the pollfds array for the VUART tty */ 68329a35f5SJeremy Kerr static const int n_internal_pollfds = 1; 69329a35f5SJeremy Kerr 70*f733c85aSJeremy Kerr /* size of the shared backlog ringbuffer */ 71*f733c85aSJeremy Kerr const size_t buffer_size = 128 * 1024; 72*f733c85aSJeremy Kerr 73769cee1aSJeremy Kerr /* state shared with the signal handler */ 74769cee1aSJeremy Kerr static bool sigint; 75329a35f5SJeremy Kerr 76d831f960SJeremy Kerr static void usage(const char *progname) 77d831f960SJeremy Kerr { 78d831f960SJeremy Kerr fprintf(stderr, 796221ce94SVishwanatha Subbanna "usage: %s [options] <DEVICE>\n" 80d831f960SJeremy Kerr "\n" 81d831f960SJeremy Kerr "Options:\n" 82d66195c1SJeremy Kerr " --config <FILE> Use FILE for configuration\n" 83d831f960SJeremy Kerr "", 84d831f960SJeremy Kerr progname); 85d831f960SJeremy Kerr } 86d831f960SJeremy Kerr 8717217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 881a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 8917217845SJeremy Kerr { 9017217845SJeremy Kerr char *tty_class_device_link; 9117217845SJeremy Kerr char *tty_device_tty_dir; 9217217845SJeremy Kerr char *tty_device_reldir; 9345ad7676SYi Li char *tty_path_input; 9445ad7676SYi Li char *tty_path_input_real; 9545ad7676SYi Li char *tty_kname_real; 9617217845SJeremy Kerr int rc; 9717217845SJeremy Kerr 9817217845SJeremy Kerr tty_class_device_link = NULL; 9917217845SJeremy Kerr tty_device_tty_dir = NULL; 10017217845SJeremy Kerr tty_device_reldir = NULL; 10145ad7676SYi Li tty_path_input = NULL; 10245ad7676SYi Li tty_path_input_real = NULL; 10345ad7676SYi Li tty_kname_real = NULL; 10417217845SJeremy Kerr 10545ad7676SYi Li /* udev may rename the tty name with a symbol link, try to resolve */ 10645ad7676SYi Li rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname); 10717217845SJeremy Kerr if (rc < 0) 10817217845SJeremy Kerr return -1; 10917217845SJeremy Kerr 11045ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 11145ad7676SYi Li if (!tty_path_input_real) { 11245ad7676SYi Li warn("Can't find realpath for /dev/%s", console->tty_kname); 11345ad7676SYi Li goto out_free; 11445ad7676SYi Li } 11545ad7676SYi Li 11645ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 11745ad7676SYi Li if (!tty_kname_real) { 11845ad7676SYi Li warn("Can't find real name for /dev/%s", console->tty_kname); 11945ad7676SYi Li goto out_free; 12045ad7676SYi Li } 12145ad7676SYi Li 12245ad7676SYi Li rc = asprintf(&tty_class_device_link, 12345ad7676SYi Li "/sys/class/tty/%s", tty_kname_real); 12445ad7676SYi Li if (rc < 0) 12545ad7676SYi Li goto out_free; 12645ad7676SYi Li 12717217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 12845ad7676SYi Li if (!tty_device_tty_dir) { 12945ad7676SYi Li warn("Can't query sysfs for device %s", tty_kname_real); 13017217845SJeremy Kerr goto out_free; 13117217845SJeremy Kerr } 13217217845SJeremy Kerr 13317217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 13417217845SJeremy Kerr if (rc < 0) 13517217845SJeremy Kerr goto out_free; 13617217845SJeremy Kerr 1371a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1381a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 13945ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 14017217845SJeremy Kerr 14145ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 14217217845SJeremy Kerr if (rc < 0) 14317217845SJeremy Kerr goto out_free; 14417217845SJeremy Kerr 14517217845SJeremy Kerr rc = 0; 14617217845SJeremy Kerr 14717217845SJeremy Kerr out_free: 14817217845SJeremy Kerr free(tty_class_device_link); 14917217845SJeremy Kerr free(tty_device_tty_dir); 15017217845SJeremy Kerr free(tty_device_reldir); 15145ad7676SYi Li free(tty_path_input); 15245ad7676SYi Li free(tty_path_input_real); 15317217845SJeremy Kerr return rc; 15417217845SJeremy Kerr } 15517217845SJeremy Kerr 1561a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 157957818b4SJeremy Kerr int value) 158957818b4SJeremy Kerr { 159957818b4SJeremy Kerr char *path; 160957818b4SJeremy Kerr FILE *fp; 161957818b4SJeremy Kerr int rc; 162957818b4SJeremy Kerr 1631a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 164957818b4SJeremy Kerr if (rc < 0) 165957818b4SJeremy Kerr return -1; 166957818b4SJeremy Kerr 167957818b4SJeremy Kerr fp = fopen(path, "w"); 168957818b4SJeremy Kerr if (!fp) { 169957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1701a0e03b4SJeremy Kerr name, console->tty_kname); 171957818b4SJeremy Kerr rc = -1; 172957818b4SJeremy Kerr goto out_free; 173957818b4SJeremy Kerr } 174957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 175957818b4SJeremy Kerr 176957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 177957818b4SJeremy Kerr if (rc < 0) 178957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1791a0e03b4SJeremy Kerr name, console->tty_kname); 180957818b4SJeremy Kerr fclose(fp); 181957818b4SJeremy Kerr 182957818b4SJeremy Kerr 183957818b4SJeremy Kerr 184957818b4SJeremy Kerr out_free: 185957818b4SJeremy Kerr free(path); 186957818b4SJeremy Kerr return rc; 187957818b4SJeremy Kerr } 188957818b4SJeremy Kerr 189d831f960SJeremy Kerr /** 19054e9569dSJeremy Kerr * Set console to raw mode: we don't want any processing to occur on 19154e9569dSJeremy Kerr * the underlying terminal input/output. 19254e9569dSJeremy Kerr */ 19354e9569dSJeremy Kerr static void tty_init_termios(struct console *console) 19454e9569dSJeremy Kerr { 19554e9569dSJeremy Kerr struct termios termios; 19654e9569dSJeremy Kerr int rc; 19754e9569dSJeremy Kerr 19854e9569dSJeremy Kerr rc = tcgetattr(console->tty_fd, &termios); 19954e9569dSJeremy Kerr if (rc) { 20054e9569dSJeremy Kerr warn("Can't read tty termios"); 20154e9569dSJeremy Kerr return; 20254e9569dSJeremy Kerr } 20354e9569dSJeremy Kerr 20454e9569dSJeremy Kerr cfmakeraw(&termios); 20554e9569dSJeremy Kerr rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 20654e9569dSJeremy Kerr if (rc) 20754e9569dSJeremy Kerr warn("Can't set terminal raw mode for tty"); 20854e9569dSJeremy Kerr } 20954e9569dSJeremy Kerr 21054e9569dSJeremy Kerr /** 211d831f960SJeremy Kerr * Open and initialise the serial device 212d831f960SJeremy Kerr */ 2131a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 214d831f960SJeremy Kerr { 2151a0e03b4SJeremy Kerr if (console->tty_sirq) 2161a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2171a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 2181a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2191a0e03b4SJeremy Kerr console->tty_lpc_addr); 220957818b4SJeremy Kerr 2211a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2221a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2231a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 224d831f960SJeremy Kerr return -1; 225d831f960SJeremy Kerr } 226d831f960SJeremy Kerr 227d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 228d831f960SJeremy Kerr * we detect larger amounts of data 229d831f960SJeremy Kerr */ 2301a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 231d831f960SJeremy Kerr 23254e9569dSJeremy Kerr tty_init_termios(console); 23354e9569dSJeremy Kerr 234329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 235329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 236329a35f5SJeremy Kerr 237d831f960SJeremy Kerr return 0; 238d831f960SJeremy Kerr } 239d831f960SJeremy Kerr 240d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 241d66195c1SJeremy Kerr { 242d66195c1SJeremy Kerr const char *val; 243d66195c1SJeremy Kerr char *endp; 244d66195c1SJeremy Kerr int rc; 245d66195c1SJeremy Kerr 246d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 247d66195c1SJeremy Kerr if (val) { 248d66195c1SJeremy Kerr console->tty_lpc_addr = strtoul(val, &endp, 0); 249d66195c1SJeremy Kerr if (endp == optarg) { 250d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 251d66195c1SJeremy Kerr return -1; 252d66195c1SJeremy Kerr } 253d66195c1SJeremy Kerr } 254d66195c1SJeremy Kerr 255d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 256d66195c1SJeremy Kerr if (val) { 257d66195c1SJeremy Kerr console->tty_sirq = strtoul(val, &endp, 0); 258d66195c1SJeremy Kerr if (endp == optarg) 259d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 260d66195c1SJeremy Kerr } 261d66195c1SJeremy Kerr 262d66195c1SJeremy Kerr if (!console->tty_kname) { 263d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 264d66195c1SJeremy Kerr return -1; 265d66195c1SJeremy Kerr } 266d66195c1SJeremy Kerr 267d66195c1SJeremy Kerr rc = tty_find_device(console); 268d66195c1SJeremy Kerr if (rc) 269d66195c1SJeremy Kerr return rc; 270d66195c1SJeremy Kerr 271d66195c1SJeremy Kerr rc = tty_init_io(console); 272d66195c1SJeremy Kerr return rc; 273d66195c1SJeremy Kerr } 274d66195c1SJeremy Kerr 2751a0e03b4SJeremy Kerr 2761a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 277d831f960SJeremy Kerr { 2781a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 279d831f960SJeremy Kerr } 280d831f960SJeremy Kerr 281d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 282d831f960SJeremy Kerr { 2831a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 2841a0e03b4SJeremy Kerr struct handler *handler; 285021b91f0SJeremy Kerr int i, rc; 286d831f960SJeremy Kerr 2871a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 2881a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 289d831f960SJeremy Kerr 2901a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 2911a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 292d831f960SJeremy Kerr 2931a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 2941a0e03b4SJeremy Kerr handler = console->handlers[i]; 2951a0e03b4SJeremy Kerr 296021b91f0SJeremy Kerr rc = 0; 2971a0e03b4SJeremy Kerr if (handler->init) 298021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 299021b91f0SJeremy Kerr 300021b91f0SJeremy Kerr handler->active = rc == 0; 301021b91f0SJeremy Kerr 302021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 303021b91f0SJeremy Kerr handler->active ? "" : "in"); 304d831f960SJeremy Kerr } 305d831f960SJeremy Kerr } 306d831f960SJeremy Kerr 3071a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 308d831f960SJeremy Kerr { 3091a0e03b4SJeremy Kerr struct handler *handler; 3101a0e03b4SJeremy Kerr int i; 3111a0e03b4SJeremy Kerr 3121a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 3131a0e03b4SJeremy Kerr handler = console->handlers[i]; 314021b91f0SJeremy Kerr if (handler->fini && handler->active) 3151a0e03b4SJeremy Kerr handler->fini(handler); 3161a0e03b4SJeremy Kerr } 317d831f960SJeremy Kerr } 318d831f960SJeremy Kerr 319*f733c85aSJeremy Kerr struct ringbuffer_consumer *console_ringbuffer_consumer_register( 320*f733c85aSJeremy Kerr struct console *console, 321*f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 322d831f960SJeremy Kerr { 323*f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 324d831f960SJeremy Kerr } 325d831f960SJeremy Kerr 32655c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 327329a35f5SJeremy Kerr struct handler *handler, poller_fn_t poller_fn, 328329a35f5SJeremy Kerr int fd, int events, void *data) 329d831f960SJeremy Kerr { 330329a35f5SJeremy Kerr struct poller *poller; 331329a35f5SJeremy Kerr int n; 332329a35f5SJeremy Kerr 333329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 334329a35f5SJeremy Kerr poller->remove = false; 335329a35f5SJeremy Kerr poller->handler = handler; 336329a35f5SJeremy Kerr poller->fn = poller_fn; 337329a35f5SJeremy Kerr poller->data = data; 338329a35f5SJeremy Kerr 339329a35f5SJeremy Kerr /* add one to our pollers array */ 340329a35f5SJeremy Kerr n = console->n_pollers++; 341329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 342329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 343329a35f5SJeremy Kerr 344329a35f5SJeremy Kerr console->pollers[n] = poller; 345329a35f5SJeremy Kerr 346329a35f5SJeremy Kerr /* increase pollfds array too */ 347329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 348329a35f5SJeremy Kerr sizeof(*console->pollfds) * 349329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 350329a35f5SJeremy Kerr 351329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 352329a35f5SJeremy Kerr memcpy(&console->pollfds[n+n_internal_pollfds], 353329a35f5SJeremy Kerr &console->pollfds[n], 354329a35f5SJeremy Kerr sizeof(*console->pollfds) * n_internal_pollfds); 355329a35f5SJeremy Kerr 356329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 357329a35f5SJeremy Kerr console->pollfds[n].events = events; 358329a35f5SJeremy Kerr 359329a35f5SJeremy Kerr return poller; 360329a35f5SJeremy Kerr } 361329a35f5SJeremy Kerr 36255c9712dSJeremy Kerr void console_poller_unregister(struct console *console, 363329a35f5SJeremy Kerr struct poller *poller) 364329a35f5SJeremy Kerr { 365329a35f5SJeremy Kerr int i; 366329a35f5SJeremy Kerr 367329a35f5SJeremy Kerr /* find the entry in our pollers array */ 368329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 369329a35f5SJeremy Kerr if (console->pollers[i] == poller) 370329a35f5SJeremy Kerr break; 371329a35f5SJeremy Kerr 372329a35f5SJeremy Kerr assert(i < console->n_pollers); 373329a35f5SJeremy Kerr 374329a35f5SJeremy Kerr console->n_pollers--; 375329a35f5SJeremy Kerr 376329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 377329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 378329a35f5SJeremy Kerr sizeof(*console->pollers) 379329a35f5SJeremy Kerr * (console->n_pollers - i)); 380329a35f5SJeremy Kerr 381329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 382329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 383329a35f5SJeremy Kerr 384329a35f5SJeremy Kerr /* ... and the pollfds array */ 385329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 386329a35f5SJeremy Kerr sizeof(*console->pollfds) * 387329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers - i)); 388329a35f5SJeremy Kerr 389329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 390329a35f5SJeremy Kerr sizeof(*console->pollfds) * 391329a35f5SJeremy Kerr (n_internal_pollfds + console->n_pollers)); 392329a35f5SJeremy Kerr 393329a35f5SJeremy Kerr 394329a35f5SJeremy Kerr free(poller); 395329a35f5SJeremy Kerr } 396329a35f5SJeremy Kerr 397329a35f5SJeremy Kerr static int call_pollers(struct console *console) 398329a35f5SJeremy Kerr { 399329a35f5SJeremy Kerr struct poller *poller; 400329a35f5SJeremy Kerr struct pollfd *pollfd; 401329a35f5SJeremy Kerr enum poller_ret prc; 402329a35f5SJeremy Kerr int i, rc; 403d831f960SJeremy Kerr 4041a0e03b4SJeremy Kerr rc = 0; 4051a0e03b4SJeremy Kerr 406329a35f5SJeremy Kerr /* 407329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 408329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 409329a35f5SJeremy Kerr */ 410329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 411329a35f5SJeremy Kerr poller = console->pollers[i]; 412329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 4131a0e03b4SJeremy Kerr 414329a35f5SJeremy Kerr if (!pollfd->revents) 4151a0e03b4SJeremy Kerr continue; 4161a0e03b4SJeremy Kerr 417329a35f5SJeremy Kerr prc = poller->fn(poller->handler, pollfd->revents, 418329a35f5SJeremy Kerr poller->data); 419329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 420329a35f5SJeremy Kerr rc = -1; 421329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 422329a35f5SJeremy Kerr poller->remove = true; 423329a35f5SJeremy Kerr } 424329a35f5SJeremy Kerr 425329a35f5SJeremy Kerr /** 426329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 427329a35f5SJeremy Kerr * the array will have changed 428329a35f5SJeremy Kerr */ 429329a35f5SJeremy Kerr for (;;) { 430329a35f5SJeremy Kerr bool removed = false; 431329a35f5SJeremy Kerr 432329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 433329a35f5SJeremy Kerr poller = console->pollers[i]; 434329a35f5SJeremy Kerr if (poller->remove) { 43555c9712dSJeremy Kerr console_poller_unregister(console, poller); 436329a35f5SJeremy Kerr removed = true; 437329a35f5SJeremy Kerr break; 438329a35f5SJeremy Kerr } 439329a35f5SJeremy Kerr } 440329a35f5SJeremy Kerr if (!removed) 441329a35f5SJeremy Kerr break; 4421a0e03b4SJeremy Kerr } 4431a0e03b4SJeremy Kerr 4441a0e03b4SJeremy Kerr return rc; 4451a0e03b4SJeremy Kerr } 4461a0e03b4SJeremy Kerr 447769cee1aSJeremy Kerr static void sighandler(int signal) 448769cee1aSJeremy Kerr { 449769cee1aSJeremy Kerr if (signal == SIGINT) 450769cee1aSJeremy Kerr sigint = true; 451769cee1aSJeremy Kerr } 452769cee1aSJeremy Kerr 4531a0e03b4SJeremy Kerr int run_console(struct console *console) 4541a0e03b4SJeremy Kerr { 455769cee1aSJeremy Kerr sighandler_t sighandler_save; 456329a35f5SJeremy Kerr int rc; 457d831f960SJeremy Kerr 458769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 459769cee1aSJeremy Kerr 460769cee1aSJeremy Kerr rc = 0; 461769cee1aSJeremy Kerr 462d831f960SJeremy Kerr for (;;) { 463d831f960SJeremy Kerr uint8_t buf[4096]; 464d831f960SJeremy Kerr 465769cee1aSJeremy Kerr if (sigint) { 466769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 467769cee1aSJeremy Kerr break; 468769cee1aSJeremy Kerr } 469769cee1aSJeremy Kerr 470329a35f5SJeremy Kerr rc = poll(console->pollfds, 471329a35f5SJeremy Kerr console->n_pollers + n_internal_pollfds, -1); 472d831f960SJeremy Kerr if (rc < 0) { 473769cee1aSJeremy Kerr if (errno == EINTR) { 474769cee1aSJeremy Kerr continue; 475769cee1aSJeremy Kerr } else { 476d831f960SJeremy Kerr warn("poll error"); 477769cee1aSJeremy Kerr break; 478769cee1aSJeremy Kerr } 479d831f960SJeremy Kerr } 480d831f960SJeremy Kerr 481329a35f5SJeremy Kerr /* process internal fd first */ 482329a35f5SJeremy Kerr BUILD_ASSERT(n_internal_pollfds == 1); 483329a35f5SJeremy Kerr 484329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 4851a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 486d831f960SJeremy Kerr if (rc <= 0) { 487d831f960SJeremy Kerr warn("Error reading from tty device"); 488769cee1aSJeremy Kerr rc = -1; 489769cee1aSJeremy Kerr break; 490d831f960SJeremy Kerr } 491*f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 4921a0e03b4SJeremy Kerr if (rc) 493769cee1aSJeremy Kerr break; 494d831f960SJeremy Kerr } 495d831f960SJeremy Kerr 496329a35f5SJeremy Kerr /* ... and then the pollers */ 497329a35f5SJeremy Kerr rc = call_pollers(console); 4981a0e03b4SJeremy Kerr if (rc) 499769cee1aSJeremy Kerr break; 5001a0e03b4SJeremy Kerr } 501769cee1aSJeremy Kerr 502769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 503769cee1aSJeremy Kerr 504769cee1aSJeremy Kerr return rc ? -1 : 0; 5051a0e03b4SJeremy Kerr } 506d831f960SJeremy Kerr static const struct option options[] = { 507d66195c1SJeremy Kerr { "config", required_argument, 0, 'c'}, 508f5858b5bSJoel Stanley { 0, 0, 0, 0}, 509d831f960SJeremy Kerr }; 510d831f960SJeremy Kerr 511d831f960SJeremy Kerr int main(int argc, char **argv) 512d831f960SJeremy Kerr { 513d66195c1SJeremy Kerr const char *config_filename = NULL; 5146221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 5151a0e03b4SJeremy Kerr struct console *console; 516d66195c1SJeremy Kerr struct config *config; 517d66195c1SJeremy Kerr int rc; 518d831f960SJeremy Kerr 519957818b4SJeremy Kerr rc = -1; 520d831f960SJeremy Kerr 521d831f960SJeremy Kerr for (;;) { 522d831f960SJeremy Kerr int c, idx; 523d831f960SJeremy Kerr 524d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 525d831f960SJeremy Kerr if (c == -1) 526d831f960SJeremy Kerr break; 527d831f960SJeremy Kerr 528d831f960SJeremy Kerr switch (c) { 529d66195c1SJeremy Kerr case 'c': 530d66195c1SJeremy Kerr config_filename = optarg; 531d831f960SJeremy Kerr break; 532d831f960SJeremy Kerr case 'h': 533d831f960SJeremy Kerr case '?': 534d831f960SJeremy Kerr usage(argv[0]); 535d66195c1SJeremy Kerr return EXIT_SUCCESS; 536d831f960SJeremy Kerr } 537d831f960SJeremy Kerr } 538d831f960SJeremy Kerr 5396221ce94SVishwanatha Subbanna if (optind >= argc) { 5406221ce94SVishwanatha Subbanna warnx("Required argument <DEVICE> missing"); 5416221ce94SVishwanatha Subbanna usage(argv[0]); 5426221ce94SVishwanatha Subbanna return EXIT_FAILURE; 5436221ce94SVishwanatha Subbanna } 5446221ce94SVishwanatha Subbanna 5456221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 5466221ce94SVishwanatha Subbanna 547d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 548d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 549329a35f5SJeremy Kerr console->pollfds = calloc(n_internal_pollfds, 550329a35f5SJeremy Kerr sizeof(*console->pollfds)); 551*f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 552329a35f5SJeremy Kerr 553d66195c1SJeremy Kerr config = config_init(config_filename); 554d66195c1SJeremy Kerr if (!config) { 555d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 556d66195c1SJeremy Kerr goto out_free; 557d831f960SJeremy Kerr } 558d831f960SJeremy Kerr 5596221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 5606221ce94SVishwanatha Subbanna 561d66195c1SJeremy Kerr rc = tty_init(console, config); 56217217845SJeremy Kerr if (rc) 563d66195c1SJeremy Kerr goto out_config_fini; 564d831f960SJeremy Kerr 565d47963e5SJeremy Kerr handlers_init(console, config); 566d831f960SJeremy Kerr 5671a0e03b4SJeremy Kerr rc = run_console(console); 568d831f960SJeremy Kerr 5691a0e03b4SJeremy Kerr handlers_fini(console); 570d831f960SJeremy Kerr 571d66195c1SJeremy Kerr out_config_fini: 572d66195c1SJeremy Kerr config_fini(config); 573d66195c1SJeremy Kerr 574957818b4SJeremy Kerr out_free: 57589ea8198SJeremy Kerr free(console->pollers); 57689ea8198SJeremy Kerr free(console->pollfds); 5771a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 5781a0e03b4SJeremy Kerr free(console->tty_dev); 5791a0e03b4SJeremy Kerr free(console); 580d831f960SJeremy Kerr 581d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 582d831f960SJeremy Kerr } 583