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 19329a35f5SJeremy Kerr #include <assert.h> 20769cee1aSJeremy Kerr #include <errno.h> 21769cee1aSJeremy Kerr #include <signal.h> 22d831f960SJeremy Kerr #include <stdint.h> 23d831f960SJeremy Kerr #include <stdbool.h> 24d831f960SJeremy Kerr #include <stdlib.h> 25d831f960SJeremy Kerr #include <stdio.h> 26d831f960SJeremy Kerr #include <fcntl.h> 27d831f960SJeremy Kerr #include <unistd.h> 28d831f960SJeremy Kerr #include <err.h> 29d831f960SJeremy Kerr #include <string.h> 30d831f960SJeremy Kerr #include <getopt.h> 317dc08baaSZev Weiss #include <glob.h> 3217217845SJeremy Kerr #include <limits.h> 331cecc5deSJohnathan Mantey #include <time.h> 3454e9569dSJeremy Kerr #include <termios.h> 35d831f960SJeremy Kerr 36d831f960SJeremy Kerr #include <sys/types.h> 371cecc5deSJohnathan Mantey #include <sys/time.h> 38b14ca19cSNinad Palsule #include <sys/socket.h> 3987e344cdSJoel Stanley #include <poll.h> 40d831f960SJeremy Kerr 411a0e03b4SJeremy Kerr #include "console-server.h" 421e04f449SAlexander Hansen #include "config.h" 43d831f960SJeremy Kerr 4430ea6385SAndrew Jeffery #define DEV_PTS_PATH "/dev/pts" 4530ea6385SAndrew Jeffery 467f2bfb9bSMedicine Yeh /* default size of the shared backlog ringbuffer */ 477f2bfb9bSMedicine Yeh const size_t default_buffer_size = 128ul * 1024ul; 48f733c85aSJeremy Kerr 49769cee1aSJeremy Kerr /* state shared with the signal handler */ 50553cb663SAndrew Jeffery static volatile sig_atomic_t sigint; 51329a35f5SJeremy Kerr 52d831f960SJeremy Kerr static void usage(const char *progname) 53d831f960SJeremy Kerr { 54d831f960SJeremy Kerr fprintf(stderr, 556221ce94SVishwanatha Subbanna "usage: %s [options] <DEVICE>\n" 56d831f960SJeremy Kerr "\n" 57d831f960SJeremy Kerr "Options:\n" 58954be0fbSAndrew Jeffery " --config <FILE>\tUse FILE for configuration\n" 59954be0fbSAndrew Jeffery " --console-id <NAME>\tUse NAME in the UNIX domain socket address\n" 60d831f960SJeremy Kerr "", 61d831f960SJeremy Kerr progname); 62d831f960SJeremy Kerr } 63d831f960SJeremy Kerr 642325d5d5SAlexander Hansen static bool console_server_pollfd_reclaimable(struct pollfd *p) 652325d5d5SAlexander Hansen { 662325d5d5SAlexander Hansen return p->fd == -1 && p->events == 0 && p->revents == ~0; 672325d5d5SAlexander Hansen } 682325d5d5SAlexander Hansen 692325d5d5SAlexander Hansen static ssize_t 702325d5d5SAlexander Hansen console_server_find_released_pollfd(struct console_server *server) 712325d5d5SAlexander Hansen { 722325d5d5SAlexander Hansen for (size_t i = 0; i < server->capacity_pollfds; i++) { 732325d5d5SAlexander Hansen struct pollfd *p = &server->pollfds[i]; 742325d5d5SAlexander Hansen if (console_server_pollfd_reclaimable(p)) { 752325d5d5SAlexander Hansen return (ssize_t)i; 762325d5d5SAlexander Hansen } 772325d5d5SAlexander Hansen } 782325d5d5SAlexander Hansen return -1; 792325d5d5SAlexander Hansen } 802325d5d5SAlexander Hansen 812325d5d5SAlexander Hansen // returns the index of that pollfd in server->pollfds 822325d5d5SAlexander Hansen // we cannot return a pointer because 'realloc' may move server->pollfds 832325d5d5SAlexander Hansen ssize_t console_server_request_pollfd(struct console_server *server, int fd, 842325d5d5SAlexander Hansen short int events) 852325d5d5SAlexander Hansen { 862325d5d5SAlexander Hansen ssize_t index; 872325d5d5SAlexander Hansen struct pollfd *pollfd; 882325d5d5SAlexander Hansen 892325d5d5SAlexander Hansen index = console_server_find_released_pollfd(server); 902325d5d5SAlexander Hansen 912325d5d5SAlexander Hansen if (index < 0) { 922325d5d5SAlexander Hansen const size_t newcap = server->capacity_pollfds + 1; 932325d5d5SAlexander Hansen 942325d5d5SAlexander Hansen struct pollfd *newarr = reallocarray(server->pollfds, newcap, 952325d5d5SAlexander Hansen sizeof(struct pollfd)); 962325d5d5SAlexander Hansen if (newarr == NULL) { 972325d5d5SAlexander Hansen return -1; 982325d5d5SAlexander Hansen } 992325d5d5SAlexander Hansen server->pollfds = newarr; 1002325d5d5SAlexander Hansen 1012325d5d5SAlexander Hansen index = (ssize_t)server->capacity_pollfds; 1022325d5d5SAlexander Hansen 1032325d5d5SAlexander Hansen server->capacity_pollfds = newcap; 1042325d5d5SAlexander Hansen } 1052325d5d5SAlexander Hansen 1062325d5d5SAlexander Hansen pollfd = &server->pollfds[index]; 1072325d5d5SAlexander Hansen pollfd->fd = fd; 1082325d5d5SAlexander Hansen pollfd->events = events; 1092325d5d5SAlexander Hansen pollfd->revents = 0; 1102325d5d5SAlexander Hansen 1112325d5d5SAlexander Hansen return index; 1122325d5d5SAlexander Hansen } 1132325d5d5SAlexander Hansen 1142325d5d5SAlexander Hansen int console_server_release_pollfd(struct console_server *server, 1152325d5d5SAlexander Hansen size_t pollfd_index) 1162325d5d5SAlexander Hansen { 1172325d5d5SAlexander Hansen if (pollfd_index >= server->capacity_pollfds) { 1182325d5d5SAlexander Hansen return -1; 1192325d5d5SAlexander Hansen } 1202325d5d5SAlexander Hansen 1212325d5d5SAlexander Hansen struct pollfd *pfd = &server->pollfds[pollfd_index]; 1222325d5d5SAlexander Hansen 1232325d5d5SAlexander Hansen // mark pollfd as reclaimable 1242325d5d5SAlexander Hansen 1252325d5d5SAlexander Hansen // ignore this file descriptor when calling 'poll' 1262325d5d5SAlexander Hansen // https://www.man7.org/linux/man-pages/man2/poll.2.html 1272325d5d5SAlexander Hansen pfd->fd = -1; 1282325d5d5SAlexander Hansen pfd->events = 0; 1292325d5d5SAlexander Hansen pfd->revents = ~0; 1302325d5d5SAlexander Hansen 1312325d5d5SAlexander Hansen return 0; 1322325d5d5SAlexander Hansen } 1332325d5d5SAlexander Hansen 134c2b0d8c7SAlexander Hansen /* populates server->tty.dev and server->tty.sysfs_devnode, using the tty kernel name */ 135c2b0d8c7SAlexander Hansen static int tty_find_device(struct console_server *server) 13617217845SJeremy Kerr { 137d3cb9c22SAndrew Jeffery char *tty_class_device_link = NULL; 138d3cb9c22SAndrew Jeffery char *tty_path_input_real = NULL; 139d3cb9c22SAndrew Jeffery char *tty_device_tty_dir = NULL; 14030ea6385SAndrew Jeffery char *tty_vuart_lpc_addr = NULL; 141d3cb9c22SAndrew Jeffery char *tty_device_reldir = NULL; 14230ea6385SAndrew Jeffery char *tty_sysfs_devnode = NULL; 143d3cb9c22SAndrew Jeffery char *tty_kname_real = NULL; 14430ea6385SAndrew Jeffery char *tty_path_input = NULL; 14517217845SJeremy Kerr int rc; 14617217845SJeremy Kerr 147c2b0d8c7SAlexander Hansen server->tty.type = TTY_DEVICE_UNDEFINED; 14830ea6385SAndrew Jeffery 149c2b0d8c7SAlexander Hansen assert(server->tty.kname); 150c2b0d8c7SAlexander Hansen if (!strlen(server->tty.kname)) { 15130ea6385SAndrew Jeffery warnx("TTY kname must not be empty"); 15230ea6385SAndrew Jeffery rc = -1; 15330ea6385SAndrew Jeffery goto out_free; 1542834c5b1SAndrew Jeffery } 15517217845SJeremy Kerr 156c2b0d8c7SAlexander Hansen if (server->tty.kname[0] == '/') { 157c2b0d8c7SAlexander Hansen tty_path_input = strdup(server->tty.kname); 15830ea6385SAndrew Jeffery if (!tty_path_input) { 15930ea6385SAndrew Jeffery rc = -1; 16030ea6385SAndrew Jeffery goto out_free; 16130ea6385SAndrew Jeffery } 16230ea6385SAndrew Jeffery } else { 163c2b0d8c7SAlexander Hansen rc = asprintf(&tty_path_input, "/dev/%s", server->tty.kname); 16430ea6385SAndrew Jeffery if (rc < 0) { 16530ea6385SAndrew Jeffery goto out_free; 16630ea6385SAndrew Jeffery } 16730ea6385SAndrew Jeffery } 16830ea6385SAndrew Jeffery 16930ea6385SAndrew Jeffery /* udev may rename the tty name with a symbol link, try to resolve */ 17045ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 17145ad7676SYi Li if (!tty_path_input_real) { 17230ea6385SAndrew Jeffery warn("Can't find realpath for %s", tty_path_input); 17315792aa7SAndrew Jeffery rc = -1; 17445ad7676SYi Li goto out_free; 17545ad7676SYi Li } 17645ad7676SYi Li 17730ea6385SAndrew Jeffery /* 17830ea6385SAndrew Jeffery * Allow hooking obmc-console-server up to PTYs for testing 17930ea6385SAndrew Jeffery * 18030ea6385SAndrew Jeffery * https://amboar.github.io/notes/2023/05/02/testing-obmc-console-with-socat.html 18130ea6385SAndrew Jeffery */ 18230ea6385SAndrew Jeffery if (!strncmp(DEV_PTS_PATH, tty_path_input_real, strlen(DEV_PTS_PATH))) { 183c2b0d8c7SAlexander Hansen server->tty.type = TTY_DEVICE_PTY; 184c2b0d8c7SAlexander Hansen server->tty.dev = strdup(server->tty.kname); 185c2b0d8c7SAlexander Hansen rc = server->tty.dev ? 0 : -1; 18630ea6385SAndrew Jeffery goto out_free; 18730ea6385SAndrew Jeffery } 18830ea6385SAndrew Jeffery 18945ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 19045ad7676SYi Li if (!tty_kname_real) { 191c2b0d8c7SAlexander Hansen warn("Can't find real name for %s", server->tty.kname); 19215792aa7SAndrew Jeffery rc = -1; 19345ad7676SYi Li goto out_free; 19445ad7676SYi Li } 19545ad7676SYi Li 196a72711afSAndrew Jeffery rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s", 197a72711afSAndrew Jeffery tty_kname_real); 1982834c5b1SAndrew Jeffery if (rc < 0) { 19945ad7676SYi Li goto out_free; 2002834c5b1SAndrew Jeffery } 20145ad7676SYi Li 20217217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 20345ad7676SYi Li if (!tty_device_tty_dir) { 20445ad7676SYi Li warn("Can't query sysfs for device %s", tty_kname_real); 20515792aa7SAndrew Jeffery rc = -1; 20617217845SJeremy Kerr goto out_free; 20717217845SJeremy Kerr } 20817217845SJeremy Kerr 20917217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 2102834c5b1SAndrew Jeffery if (rc < 0) { 21117217845SJeremy Kerr goto out_free; 2122834c5b1SAndrew Jeffery } 21317217845SJeremy Kerr 21430ea6385SAndrew Jeffery tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 21530ea6385SAndrew Jeffery if (!tty_sysfs_devnode) { 21645ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 2172834c5b1SAndrew Jeffery } 21817217845SJeremy Kerr 219c2b0d8c7SAlexander Hansen rc = asprintf(&server->tty.dev, "/dev/%s", tty_kname_real); 2202834c5b1SAndrew Jeffery if (rc < 0) { 22117217845SJeremy Kerr goto out_free; 2222834c5b1SAndrew Jeffery } 22317217845SJeremy Kerr 224955d140eSOskar Senft // Default to non-VUART 225c2b0d8c7SAlexander Hansen server->tty.type = TTY_DEVICE_UART; 226955d140eSOskar Senft 22730ea6385SAndrew Jeffery /* Arbitrarily pick an attribute to differentiate UART vs VUART */ 228955d140eSOskar Senft if (tty_sysfs_devnode) { 229955d140eSOskar Senft rc = asprintf(&tty_vuart_lpc_addr, "%s/lpc_address", 230955d140eSOskar Senft tty_sysfs_devnode); 23130ea6385SAndrew Jeffery if (rc < 0) { 23230ea6385SAndrew Jeffery goto out_free; 23330ea6385SAndrew Jeffery } 23430ea6385SAndrew Jeffery 23530ea6385SAndrew Jeffery rc = access(tty_vuart_lpc_addr, F_OK); 236955d140eSOskar Senft if (!rc) { 237c2b0d8c7SAlexander Hansen server->tty.type = TTY_DEVICE_VUART; 238c2b0d8c7SAlexander Hansen server->tty.vuart.sysfs_devnode = 239955d140eSOskar Senft strdup(tty_sysfs_devnode); 240955d140eSOskar Senft } 241955d140eSOskar Senft } 24230ea6385SAndrew Jeffery 24317217845SJeremy Kerr rc = 0; 24417217845SJeremy Kerr 24517217845SJeremy Kerr out_free: 24630ea6385SAndrew Jeffery free(tty_vuart_lpc_addr); 24717217845SJeremy Kerr free(tty_class_device_link); 248982090d9SAndrew Jeffery free(tty_sysfs_devnode); 24917217845SJeremy Kerr free(tty_device_tty_dir); 25017217845SJeremy Kerr free(tty_device_reldir); 25145ad7676SYi Li free(tty_path_input); 25245ad7676SYi Li free(tty_path_input_real); 25317217845SJeremy Kerr return rc; 25417217845SJeremy Kerr } 25517217845SJeremy Kerr 256c2b0d8c7SAlexander Hansen static int tty_set_sysfs_attr(struct console_server *server, const char *name, 257957818b4SJeremy Kerr int value) 258957818b4SJeremy Kerr { 259957818b4SJeremy Kerr char *path; 260957818b4SJeremy Kerr FILE *fp; 261957818b4SJeremy Kerr int rc; 262957818b4SJeremy Kerr 263c2b0d8c7SAlexander Hansen assert(server->tty.type == TTY_DEVICE_VUART); 26430ea6385SAndrew Jeffery 265c2b0d8c7SAlexander Hansen if (!server->tty.vuart.sysfs_devnode) { 26630ea6385SAndrew Jeffery return -1; 26730ea6385SAndrew Jeffery } 26830ea6385SAndrew Jeffery 269c2b0d8c7SAlexander Hansen rc = asprintf(&path, "%s/%s", server->tty.vuart.sysfs_devnode, name); 2702834c5b1SAndrew Jeffery if (rc < 0) { 271957818b4SJeremy Kerr return -1; 2722834c5b1SAndrew Jeffery } 273957818b4SJeremy Kerr 274957818b4SJeremy Kerr fp = fopen(path, "w"); 275957818b4SJeremy Kerr if (!fp) { 276a72711afSAndrew Jeffery warn("Can't access attribute %s on device %s", name, 277c2b0d8c7SAlexander Hansen server->tty.kname); 278957818b4SJeremy Kerr rc = -1; 279957818b4SJeremy Kerr goto out_free; 280957818b4SJeremy Kerr } 281957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 282957818b4SJeremy Kerr 283957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 2842834c5b1SAndrew Jeffery if (rc < 0) { 285a72711afSAndrew Jeffery warn("Error writing to %s attribute of device %s", name, 286c2b0d8c7SAlexander Hansen server->tty.kname); 2872834c5b1SAndrew Jeffery } 288957818b4SJeremy Kerr fclose(fp); 289957818b4SJeremy Kerr 290957818b4SJeremy Kerr out_free: 291957818b4SJeremy Kerr free(path); 292957818b4SJeremy Kerr return rc; 293957818b4SJeremy Kerr } 294957818b4SJeremy Kerr 295d831f960SJeremy Kerr /** 296c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 29754e9569dSJeremy Kerr */ 298c2b0d8c7SAlexander Hansen void tty_init_termios(struct console_server *server) 29954e9569dSJeremy Kerr { 30054e9569dSJeremy Kerr struct termios termios; 30154e9569dSJeremy Kerr int rc; 30254e9569dSJeremy Kerr 303c2b0d8c7SAlexander Hansen rc = tcgetattr(server->tty.fd, &termios); 30454e9569dSJeremy Kerr if (rc) { 30554e9569dSJeremy Kerr warn("Can't read tty termios"); 30654e9569dSJeremy Kerr return; 30754e9569dSJeremy Kerr } 30854e9569dSJeremy Kerr 309c2b0d8c7SAlexander Hansen if (server->tty.type == TTY_DEVICE_UART && server->tty.uart.baud) { 310c2b0d8c7SAlexander Hansen if (cfsetspeed(&termios, server->tty.uart.baud) < 0) { 311c2b0d8c7SAlexander Hansen warn("Couldn't set speeds for %s", server->tty.kname); 312c7fbcd48SBenjamin Fair } 3132834c5b1SAndrew Jeffery } 314c7fbcd48SBenjamin Fair 315c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 316c7fbcd48SBenjamin Fair * the underlying terminal input/output. 317c7fbcd48SBenjamin Fair */ 31854e9569dSJeremy Kerr cfmakeraw(&termios); 319c7fbcd48SBenjamin Fair 320c2b0d8c7SAlexander Hansen rc = tcsetattr(server->tty.fd, TCSANOW, &termios); 3212834c5b1SAndrew Jeffery if (rc) { 322c2b0d8c7SAlexander Hansen warn("Can't set terminal options for %s", server->tty.kname); 32354e9569dSJeremy Kerr } 3242834c5b1SAndrew Jeffery } 32554e9569dSJeremy Kerr 32654e9569dSJeremy Kerr /** 327d831f960SJeremy Kerr * Open and initialise the serial device 328d831f960SJeremy Kerr */ 329c2b0d8c7SAlexander Hansen static void tty_init_vuart_io(struct console_server *server) 330d831f960SJeremy Kerr { 331c2b0d8c7SAlexander Hansen assert(server->tty.type == TTY_DEVICE_VUART); 33230ea6385SAndrew Jeffery 333c2b0d8c7SAlexander Hansen if (server->tty.vuart.sirq) { 334c2b0d8c7SAlexander Hansen tty_set_sysfs_attr(server, "sirq", server->tty.vuart.sirq); 3352834c5b1SAndrew Jeffery } 336957818b4SJeremy Kerr 337c2b0d8c7SAlexander Hansen if (server->tty.vuart.lpc_addr) { 338c2b0d8c7SAlexander Hansen tty_set_sysfs_attr(server, "lpc_address", 339c2b0d8c7SAlexander Hansen server->tty.vuart.lpc_addr); 34030ea6385SAndrew Jeffery } 34130ea6385SAndrew Jeffery } 34230ea6385SAndrew Jeffery 343c2b0d8c7SAlexander Hansen static int tty_init_io(struct console_server *server) 34430ea6385SAndrew Jeffery { 345c2b0d8c7SAlexander Hansen server->tty.fd = open(server->tty.dev, O_RDWR); 346c2b0d8c7SAlexander Hansen if (server->tty.fd <= 0) { 347c2b0d8c7SAlexander Hansen warn("Can't open tty %s", server->tty.dev); 348d831f960SJeremy Kerr return -1; 349d831f960SJeremy Kerr } 350d831f960SJeremy Kerr 351d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 352d831f960SJeremy Kerr * we detect larger amounts of data 353d831f960SJeremy Kerr */ 354c2b0d8c7SAlexander Hansen fcntl(server->tty.fd, F_SETFL, FNDELAY); 355d831f960SJeremy Kerr 356c2b0d8c7SAlexander Hansen tty_init_termios(server); 35754e9569dSJeremy Kerr 3582325d5d5SAlexander Hansen ssize_t index = 3592325d5d5SAlexander Hansen console_server_request_pollfd(server, server->tty.fd, POLLIN); 3602325d5d5SAlexander Hansen 3612325d5d5SAlexander Hansen if (index < 0) { 3622325d5d5SAlexander Hansen return -1; 3632325d5d5SAlexander Hansen } 3642325d5d5SAlexander Hansen 3652325d5d5SAlexander Hansen server->tty_pollfd_index = (size_t)index; 366329a35f5SJeremy Kerr 367d831f960SJeremy Kerr return 0; 368d831f960SJeremy Kerr } 369d831f960SJeremy Kerr 370c2b0d8c7SAlexander Hansen static int tty_init_vuart(struct console_server *server, struct config *config) 371d66195c1SJeremy Kerr { 372fd883a88SAndrew Jeffery unsigned long parsed; 373d66195c1SJeremy Kerr const char *val; 374d66195c1SJeremy Kerr char *endp; 37530ea6385SAndrew Jeffery 376c2b0d8c7SAlexander Hansen assert(server->tty.type == TTY_DEVICE_VUART); 377d66195c1SJeremy Kerr 378d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 379d66195c1SJeremy Kerr if (val) { 380fd883a88SAndrew Jeffery errno = 0; 381fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 382fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 383fd883a88SAndrew Jeffery warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'", 384fd883a88SAndrew Jeffery val); 385fd883a88SAndrew Jeffery return -1; 386fd883a88SAndrew Jeffery } 387fd883a88SAndrew Jeffery 388fd883a88SAndrew Jeffery if (parsed > UINT16_MAX) { 389fd883a88SAndrew Jeffery warn("Invalid LPC address '%s'", val); 390fd883a88SAndrew Jeffery return -1; 391fd883a88SAndrew Jeffery } 392fd883a88SAndrew Jeffery 393c2b0d8c7SAlexander Hansen server->tty.vuart.lpc_addr = (uint16_t)parsed; 394d66195c1SJeremy Kerr if (endp == optarg) { 395d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 396d66195c1SJeremy Kerr return -1; 397d66195c1SJeremy Kerr } 398d66195c1SJeremy Kerr } 399d66195c1SJeremy Kerr 400d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 401d66195c1SJeremy Kerr if (val) { 402fd883a88SAndrew Jeffery errno = 0; 403fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 404fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 405fd883a88SAndrew Jeffery warn("Cannot interpret 'sirq' value as an unsigned long: '%s'", 406fd883a88SAndrew Jeffery val); 407fd883a88SAndrew Jeffery } 408fd883a88SAndrew Jeffery 4092834c5b1SAndrew Jeffery if (parsed > 16) { 410fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 4112834c5b1SAndrew Jeffery } 412fd883a88SAndrew Jeffery 413c2b0d8c7SAlexander Hansen server->tty.vuart.sirq = (int)parsed; 4142834c5b1SAndrew Jeffery if (endp == optarg) { 415d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 416d66195c1SJeremy Kerr } 4172834c5b1SAndrew Jeffery } 418d66195c1SJeremy Kerr 41930ea6385SAndrew Jeffery return 0; 4202834c5b1SAndrew Jeffery } 421c7fbcd48SBenjamin Fair 422c2b0d8c7SAlexander Hansen static int tty_init(struct console_server *server, struct config *config, 42330ea6385SAndrew Jeffery const char *tty_arg) 42430ea6385SAndrew Jeffery { 42530ea6385SAndrew Jeffery const char *val; 42630ea6385SAndrew Jeffery int rc; 42730ea6385SAndrew Jeffery 428d769eecfSAndrew Jeffery if (tty_arg) { 429c2b0d8c7SAlexander Hansen server->tty.kname = tty_arg; 430d769eecfSAndrew Jeffery } else if ((val = config_get_value(config, "upstream-tty"))) { 431c2b0d8c7SAlexander Hansen server->tty.kname = val; 432d769eecfSAndrew Jeffery } else { 433d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 434d66195c1SJeremy Kerr return -1; 435d66195c1SJeremy Kerr } 436d66195c1SJeremy Kerr 437c2b0d8c7SAlexander Hansen rc = tty_find_device(server); 4382834c5b1SAndrew Jeffery if (rc) { 439d66195c1SJeremy Kerr return rc; 4402834c5b1SAndrew Jeffery } 441d66195c1SJeremy Kerr 442c2b0d8c7SAlexander Hansen switch (server->tty.type) { 44330ea6385SAndrew Jeffery case TTY_DEVICE_VUART: 444c2b0d8c7SAlexander Hansen rc = tty_init_vuart(server, config); 44530ea6385SAndrew Jeffery if (rc) { 446d66195c1SJeremy Kerr return rc; 447d66195c1SJeremy Kerr } 448d66195c1SJeremy Kerr 449c2b0d8c7SAlexander Hansen tty_init_vuart_io(server); 45030ea6385SAndrew Jeffery break; 45130ea6385SAndrew Jeffery case TTY_DEVICE_UART: 45230ea6385SAndrew Jeffery val = config_get_value(config, "baud"); 45330ea6385SAndrew Jeffery if (val) { 454c2b0d8c7SAlexander Hansen if (config_parse_baud(&server->tty.uart.baud, val)) { 45530ea6385SAndrew Jeffery warnx("Invalid baud rate: '%s'", val); 45630ea6385SAndrew Jeffery } 45730ea6385SAndrew Jeffery } 45830ea6385SAndrew Jeffery break; 45930ea6385SAndrew Jeffery case TTY_DEVICE_PTY: 46030ea6385SAndrew Jeffery break; 46130ea6385SAndrew Jeffery case TTY_DEVICE_UNDEFINED: 46230ea6385SAndrew Jeffery default: 46330ea6385SAndrew Jeffery warnx("Cannot configure unrecognised TTY device"); 46430ea6385SAndrew Jeffery return -1; 46530ea6385SAndrew Jeffery } 46630ea6385SAndrew Jeffery 467c2b0d8c7SAlexander Hansen return tty_init_io(server); 46830ea6385SAndrew Jeffery } 46930ea6385SAndrew Jeffery 470c2b0d8c7SAlexander Hansen static void tty_fini(struct console_server *server) 47130ea6385SAndrew Jeffery { 4722325d5d5SAlexander Hansen if (server->tty_pollfd_index < server->capacity_pollfds) { 4732325d5d5SAlexander Hansen console_server_release_pollfd(server, server->tty_pollfd_index); 4742325d5d5SAlexander Hansen server->tty_pollfd_index = SIZE_MAX; 4752325d5d5SAlexander Hansen } 4762325d5d5SAlexander Hansen 477c2b0d8c7SAlexander Hansen if (server->tty.type == TTY_DEVICE_VUART) { 478c2b0d8c7SAlexander Hansen free(server->tty.vuart.sysfs_devnode); 47930ea6385SAndrew Jeffery } 4802325d5d5SAlexander Hansen 481c2b0d8c7SAlexander Hansen free(server->tty.dev); 48230ea6385SAndrew Jeffery } 48330ea6385SAndrew Jeffery 4847dc08baaSZev Weiss static int write_to_path(const char *path, const char *data) 4857dc08baaSZev Weiss { 4867dc08baaSZev Weiss int rc = 0; 4877dc08baaSZev Weiss FILE *f = fopen(path, "w"); 4887dc08baaSZev Weiss if (!f) { 4897dc08baaSZev Weiss return -1; 4907dc08baaSZev Weiss } 4917dc08baaSZev Weiss 4927dc08baaSZev Weiss if (fprintf(f, "%s", data) < 0) { 4937dc08baaSZev Weiss rc = -1; 4947dc08baaSZev Weiss } 4957dc08baaSZev Weiss 4967dc08baaSZev Weiss if (fclose(f)) { 4977dc08baaSZev Weiss rc = -1; 4987dc08baaSZev Weiss } 4997dc08baaSZev Weiss 5007dc08baaSZev Weiss return rc; 5017dc08baaSZev Weiss } 5027dc08baaSZev Weiss 5037dc08baaSZev Weiss #define ASPEED_UART_ROUTING_PATTERN \ 5047dc08baaSZev Weiss "/sys/bus/platform/drivers/aspeed-uart-routing/*.uart-routing" 5057dc08baaSZev Weiss 5067dc08baaSZev Weiss static void uart_routing_init(struct config *config) 5077dc08baaSZev Weiss { 5087dc08baaSZev Weiss const char *muxcfg; 5097dc08baaSZev Weiss const char *p; 5107dc08baaSZev Weiss size_t buflen; 5117dc08baaSZev Weiss char *sink; 5127dc08baaSZev Weiss char *source; 5137dc08baaSZev Weiss char *muxdir; 5147dc08baaSZev Weiss char *path; 5157dc08baaSZev Weiss glob_t globbuf; 5167dc08baaSZev Weiss 5177dc08baaSZev Weiss muxcfg = config_get_value(config, "aspeed-uart-routing"); 5187dc08baaSZev Weiss if (!muxcfg) { 5197dc08baaSZev Weiss return; 5207dc08baaSZev Weiss } 5217dc08baaSZev Weiss 5227dc08baaSZev Weiss /* Find the driver's sysfs directory */ 5237dc08baaSZev Weiss if (glob(ASPEED_UART_ROUTING_PATTERN, GLOB_ERR | GLOB_NOSORT, NULL, 5247dc08baaSZev Weiss &globbuf) != 0) { 5257dc08baaSZev Weiss warn("Couldn't find uart-routing driver directory, cannot apply config"); 5267dc08baaSZev Weiss return; 5277dc08baaSZev Weiss } 5287dc08baaSZev Weiss if (globbuf.gl_pathc != 1) { 5297dc08baaSZev Weiss warnx("Found %zd uart-routing driver directories, cannot apply config", 5307dc08baaSZev Weiss globbuf.gl_pathc); 5317dc08baaSZev Weiss goto out_free_glob; 5327dc08baaSZev Weiss } 5337dc08baaSZev Weiss muxdir = globbuf.gl_pathv[0]; 5347dc08baaSZev Weiss 5357dc08baaSZev Weiss /* 5367dc08baaSZev Weiss * Rather than faff about tracking a bunch of separate buffer sizes, 5377dc08baaSZev Weiss * just use one (worst-case) size for all of them -- +2 for a trailing 5387dc08baaSZev Weiss * NUL and a '/' separator to construct the sysfs file path. 5397dc08baaSZev Weiss */ 5407dc08baaSZev Weiss buflen = strlen(muxdir) + strlen(muxcfg) + 2; 5417dc08baaSZev Weiss 5427dc08baaSZev Weiss sink = malloc(buflen); 5437dc08baaSZev Weiss source = malloc(buflen); 5447dc08baaSZev Weiss path = malloc(buflen); 5457dc08baaSZev Weiss if (!path || !sink || !source) { 5467dc08baaSZev Weiss warnx("Out of memory applying uart routing config"); 5477dc08baaSZev Weiss goto out_free_bufs; 5487dc08baaSZev Weiss } 5497dc08baaSZev Weiss 5507dc08baaSZev Weiss p = muxcfg; 5517dc08baaSZev Weiss while (*p) { 5527dc08baaSZev Weiss ssize_t bytes_scanned; 5537dc08baaSZev Weiss 5547dc08baaSZev Weiss if (sscanf(p, " %[^:/ \t]:%[^: \t] %zn", sink, source, 5557dc08baaSZev Weiss &bytes_scanned) != 2) { 5567dc08baaSZev Weiss warnx("Invalid syntax in aspeed uart config: '%s' not applied", 5577dc08baaSZev Weiss p); 5587dc08baaSZev Weiss break; 5597dc08baaSZev Weiss } 5607dc08baaSZev Weiss p += bytes_scanned; 5617dc08baaSZev Weiss 5627dc08baaSZev Weiss /* 5637dc08baaSZev Weiss * Check that the sink name looks reasonable before proceeding 5647dc08baaSZev Weiss * (there are other writable files in the same directory that 5657dc08baaSZev Weiss * we shouldn't be touching, such as 'driver_override' and 5667dc08baaSZev Weiss * 'uevent'). 5677dc08baaSZev Weiss */ 5687dc08baaSZev Weiss if (strncmp(sink, "io", strlen("io")) != 0 && 5697dc08baaSZev Weiss strncmp(sink, "uart", strlen("uart")) != 0) { 5707dc08baaSZev Weiss warnx("Skipping invalid uart routing name '%s' (must be ioN or uartN)", 5717dc08baaSZev Weiss sink); 5727dc08baaSZev Weiss continue; 5737dc08baaSZev Weiss } 5747dc08baaSZev Weiss 5757dc08baaSZev Weiss snprintf(path, buflen, "%s/%s", muxdir, sink); 5767dc08baaSZev Weiss if (write_to_path(path, source)) { 5777dc08baaSZev Weiss warn("Failed to apply uart-routing config '%s:%s'", 5787dc08baaSZev Weiss sink, source); 5797dc08baaSZev Weiss } 5807dc08baaSZev Weiss } 5817dc08baaSZev Weiss 5827dc08baaSZev Weiss out_free_bufs: 5837dc08baaSZev Weiss free(path); 5847dc08baaSZev Weiss free(source); 5857dc08baaSZev Weiss free(sink); 5867dc08baaSZev Weiss out_free_glob: 5877dc08baaSZev Weiss globfree(&globbuf); 5887dc08baaSZev Weiss } 5897dc08baaSZev Weiss 5901a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 591d831f960SJeremy Kerr { 592c2b0d8c7SAlexander Hansen return write_buf_to_fd(console->server->tty.fd, data, len); 593d831f960SJeremy Kerr } 594d831f960SJeremy Kerr 5955ba20b5bSNinad Palsule /* Prepare a socket name */ 596954be0fbSAndrew Jeffery static int set_socket_info(struct console *console, struct config *config, 597954be0fbSAndrew Jeffery const char *console_id) 598b14ca19cSNinad Palsule { 599b14ca19cSNinad Palsule ssize_t len; 600b14ca19cSNinad Palsule 6015ba20b5bSNinad Palsule /* Get console id */ 6025ba20b5bSNinad Palsule console->console_id = config_resolve_console_id(config, console_id); 603954be0fbSAndrew Jeffery 604b14ca19cSNinad Palsule /* Get the socket name/path */ 6055ba20b5bSNinad Palsule len = console_socket_path(console->socket_name, console->console_id); 606b14ca19cSNinad Palsule if (len < 0) { 607b14ca19cSNinad Palsule warn("Failed to set socket path: %s", strerror(errno)); 608b14ca19cSNinad Palsule return EXIT_FAILURE; 609b14ca19cSNinad Palsule } 610b14ca19cSNinad Palsule 611b14ca19cSNinad Palsule /* Socket name is not a null terminated string hence save the length */ 612b14ca19cSNinad Palsule console->socket_name_len = len; 613b14ca19cSNinad Palsule 614b14ca19cSNinad Palsule return 0; 615b14ca19cSNinad Palsule } 616b14ca19cSNinad Palsule 617d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 618d831f960SJeremy Kerr { 619b70f8713SAndrew Jeffery /* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 620adedc333SAndrew Jeffery extern const struct handler_type *const __start_handlers[]; 621adedc333SAndrew Jeffery extern const struct handler_type *const __stop_handlers[]; 622b70f8713SAndrew Jeffery /* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 623e2826c7dSJeremy Kerr size_t n_types; 624e2826c7dSJeremy Kerr int j = 0; 625e2826c7dSJeremy Kerr size_t i; 626e2826c7dSJeremy Kerr 627adedc333SAndrew Jeffery n_types = __stop_handlers - __start_handlers; 628e2826c7dSJeremy Kerr console->handlers = calloc(n_types, sizeof(struct handler *)); 629e2826c7dSJeremy Kerr if (!console->handlers) { 630e2826c7dSJeremy Kerr err(EXIT_FAILURE, "malloc(handlers)"); 631e2826c7dSJeremy Kerr } 632e2826c7dSJeremy Kerr 633079fc516SAndrew Jeffery printf("%zu handler type%s\n", n_types, n_types == 1 ? "" : "s"); 634e2826c7dSJeremy Kerr 635e2826c7dSJeremy Kerr for (i = 0; i < n_types; i++) { 636adedc333SAndrew Jeffery const struct handler_type *type = __start_handlers[i]; 6371a0e03b4SJeremy Kerr struct handler *handler; 638d831f960SJeremy Kerr 639e2826c7dSJeremy Kerr /* Should be picked up at build time by 640e2826c7dSJeremy Kerr * console_handler_register, but check anyway 641e2826c7dSJeremy Kerr */ 642e2826c7dSJeremy Kerr if (!type->init || !type->fini) { 643e2826c7dSJeremy Kerr errx(EXIT_FAILURE, 644e2826c7dSJeremy Kerr "invalid handler type %s: no init() / fini()", 645e2826c7dSJeremy Kerr type->name); 6462834c5b1SAndrew Jeffery } 647021b91f0SJeremy Kerr 648e2826c7dSJeremy Kerr handler = type->init(type, console, config); 649021b91f0SJeremy Kerr 650e2826c7dSJeremy Kerr printf(" console '%s': handler %s [%sactive]\n", 651e2826c7dSJeremy Kerr console->console_id, type->name, handler ? "" : "in"); 652e2826c7dSJeremy Kerr 653e2826c7dSJeremy Kerr if (handler) { 654e2826c7dSJeremy Kerr handler->type = type; 655e2826c7dSJeremy Kerr console->handlers[j++] = handler; 656d831f960SJeremy Kerr } 657d831f960SJeremy Kerr } 658d831f960SJeremy Kerr 659e2826c7dSJeremy Kerr console->n_handlers = j; 660e2826c7dSJeremy Kerr } 661e2826c7dSJeremy Kerr 6621a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 663d831f960SJeremy Kerr { 6641a0e03b4SJeremy Kerr struct handler *handler; 6651a0e03b4SJeremy Kerr int i; 6661a0e03b4SJeremy Kerr 6671a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 6681a0e03b4SJeremy Kerr handler = console->handlers[i]; 669e2826c7dSJeremy Kerr handler->type->fini(handler); 6701a0e03b4SJeremy Kerr } 671e2826c7dSJeremy Kerr 672e2826c7dSJeremy Kerr free(console->handlers); 673e2826c7dSJeremy Kerr console->handlers = NULL; 674e2826c7dSJeremy Kerr console->n_handlers = 0; 6752834c5b1SAndrew Jeffery } 676d831f960SJeremy Kerr 6771cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 6781cecc5deSJohnathan Mantey { 6791cecc5deSJohnathan Mantey struct timespec t; 6801cecc5deSJohnathan Mantey int rc; 6811cecc5deSJohnathan Mantey 6821cecc5deSJohnathan Mantey /* 6831cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 6841cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 6851cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 6861cecc5deSJohnathan Mantey */ 6871cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 6882834c5b1SAndrew Jeffery if (rc) { 6891cecc5deSJohnathan Mantey return rc; 6902834c5b1SAndrew Jeffery } 6911cecc5deSJohnathan Mantey 6921cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 6931cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 6941cecc5deSJohnathan Mantey 6951cecc5deSJohnathan Mantey return 0; 6961cecc5deSJohnathan Mantey } 6971cecc5deSJohnathan Mantey 698a72711afSAndrew Jeffery struct ringbuffer_consumer * 699a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console, 700f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 701d831f960SJeremy Kerr { 702f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 703d831f960SJeremy Kerr } 704d831f960SJeremy Kerr 70555c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 706a72711afSAndrew Jeffery struct handler *handler, 707a72711afSAndrew Jeffery poller_event_fn_t poller_fn, 7081cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 7091cecc5deSJohnathan Mantey int events, void *data) 710d831f960SJeremy Kerr { 711329a35f5SJeremy Kerr struct poller *poller; 7125c359cc6SAndrew Jeffery long n; 713329a35f5SJeremy Kerr 7142325d5d5SAlexander Hansen const ssize_t index = console_server_request_pollfd( 7152325d5d5SAlexander Hansen console->server, fd, (short)(events & 0x7fff)); 7162325d5d5SAlexander Hansen if (index < 0) { 7172325d5d5SAlexander Hansen fprintf(stderr, "Error requesting pollfd\n"); 7182325d5d5SAlexander Hansen return NULL; 7192325d5d5SAlexander Hansen } 7202325d5d5SAlexander Hansen 721329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 7222325d5d5SAlexander Hansen // TODO: check for error case of malloc here and release previously requested pollfd 723329a35f5SJeremy Kerr poller->remove = false; 724329a35f5SJeremy Kerr poller->handler = handler; 7251cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 7261cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 7279cc8459aSAndrew Jeffery timerclear(&poller->timeout); 728329a35f5SJeremy Kerr poller->data = data; 7292325d5d5SAlexander Hansen poller->pollfd_index = index; 730329a35f5SJeremy Kerr 731329a35f5SJeremy Kerr /* add one to our pollers array */ 732329a35f5SJeremy Kerr n = console->n_pollers++; 73391b52175SAndrew Jeffery /* 73491b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 73591b52175SAndrew Jeffery * pointer type. 73691b52175SAndrew Jeffery */ 73791b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 73891b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 73991b52175SAndrew Jeffery sizeof(*console->pollers)); 7402325d5d5SAlexander Hansen // TODO: check for the error case of reallocarray and release previously requested pollfd 74191b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 742329a35f5SJeremy Kerr 743329a35f5SJeremy Kerr console->pollers[n] = poller; 744329a35f5SJeremy Kerr 745329a35f5SJeremy Kerr return poller; 746329a35f5SJeremy Kerr } 747329a35f5SJeremy Kerr 748a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller) 749329a35f5SJeremy Kerr { 750329a35f5SJeremy Kerr int i; 751329a35f5SJeremy Kerr 752329a35f5SJeremy Kerr /* find the entry in our pollers array */ 7532834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 7542834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 755329a35f5SJeremy Kerr break; 7562834c5b1SAndrew Jeffery } 7572834c5b1SAndrew Jeffery } 758329a35f5SJeremy Kerr 759329a35f5SJeremy Kerr assert(i < console->n_pollers); 760329a35f5SJeremy Kerr 761329a35f5SJeremy Kerr console->n_pollers--; 762329a35f5SJeremy Kerr 76391b52175SAndrew Jeffery /* 76491b52175SAndrew Jeffery * Remove the item from the pollers array... 76591b52175SAndrew Jeffery * 76691b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 76791b52175SAndrew Jeffery * pointer type. 76891b52175SAndrew Jeffery */ 76991b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 770329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i + 1], 771a72711afSAndrew Jeffery sizeof(*console->pollers) * (console->n_pollers - i)); 772329a35f5SJeremy Kerr 7737851a396SAndrew Jeffery if (console->n_pollers == 0) { 7747851a396SAndrew Jeffery free(console->pollers); 7757851a396SAndrew Jeffery console->pollers = NULL; 7767851a396SAndrew Jeffery } else { 7777851a396SAndrew Jeffery console->pollers = reallocarray(console->pollers, 7787851a396SAndrew Jeffery console->n_pollers, 77991b52175SAndrew Jeffery sizeof(*console->pollers)); 7807851a396SAndrew Jeffery } 78191b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 782329a35f5SJeremy Kerr 7832325d5d5SAlexander Hansen console_server_release_pollfd(console->server, poller->pollfd_index); 784329a35f5SJeremy Kerr 785329a35f5SJeremy Kerr free(poller); 786329a35f5SJeremy Kerr } 787329a35f5SJeremy Kerr 7886b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 7896b1fed27SJeremy Kerr int events) 7906b1fed27SJeremy Kerr { 7912325d5d5SAlexander Hansen console->server->pollfds[poller->pollfd_index].events = 7922325d5d5SAlexander Hansen (short)(events & 0x7fff); 7936b1fed27SJeremy Kerr } 7946b1fed27SJeremy Kerr 795fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 796fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 7971cecc5deSJohnathan Mantey { 7981cecc5deSJohnathan Mantey struct timeval now; 7991cecc5deSJohnathan Mantey int rc; 8001cecc5deSJohnathan Mantey 8011cecc5deSJohnathan Mantey rc = get_current_time(&now); 8022834c5b1SAndrew Jeffery if (rc) { 8031cecc5deSJohnathan Mantey return; 8042834c5b1SAndrew Jeffery } 8051cecc5deSJohnathan Mantey 8061cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 8071cecc5deSJohnathan Mantey } 8081cecc5deSJohnathan Mantey 8095c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time) 8101cecc5deSJohnathan Mantey { 811b70f8713SAndrew Jeffery struct timeval *earliest; 812b70f8713SAndrew Jeffery struct timeval interval; 8131cecc5deSJohnathan Mantey struct poller *poller; 8141cecc5deSJohnathan Mantey int i; 8151cecc5deSJohnathan Mantey 8161cecc5deSJohnathan Mantey earliest = NULL; 8171cecc5deSJohnathan Mantey 8181cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 8191cecc5deSJohnathan Mantey poller = console->pollers[i]; 8201cecc5deSJohnathan Mantey 8211cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 8221cecc5deSJohnathan Mantey (!earliest || 8231cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))) { 8241cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 8251cecc5deSJohnathan Mantey // function to timeout. 8261cecc5deSJohnathan Mantey earliest = &poller->timeout; 8271cecc5deSJohnathan Mantey } 8281cecc5deSJohnathan Mantey } 8291cecc5deSJohnathan Mantey 8301cecc5deSJohnathan Mantey if (earliest) { 8311cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 8321cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 8331cecc5deSJohnathan Mantey * not elapsed */ 8341cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 8351cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 8361cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 8370b7b0477SAndrew Jeffery } /* return from poll immediately */ 8381cecc5deSJohnathan Mantey return 0; 8390b7b0477SAndrew Jeffery 8400b7b0477SAndrew Jeffery } /* poll indefinitely */ 8411cecc5deSJohnathan Mantey return -1; 8421cecc5deSJohnathan Mantey } 8431cecc5deSJohnathan Mantey 8441cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 845329a35f5SJeremy Kerr { 846329a35f5SJeremy Kerr struct poller *poller; 847329a35f5SJeremy Kerr struct pollfd *pollfd; 848329a35f5SJeremy Kerr enum poller_ret prc; 849b70f8713SAndrew Jeffery int i; 850b70f8713SAndrew Jeffery int rc; 851d831f960SJeremy Kerr 8521a0e03b4SJeremy Kerr rc = 0; 8531a0e03b4SJeremy Kerr 854329a35f5SJeremy Kerr /* 855329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 856329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 857329a35f5SJeremy Kerr */ 858329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 859329a35f5SJeremy Kerr poller = console->pollers[i]; 8602325d5d5SAlexander Hansen pollfd = &console->server->pollfds[poller->pollfd_index]; 8612325d5d5SAlexander Hansen if (pollfd->fd < 0) { 8622325d5d5SAlexander Hansen // pollfd has already been released 8632325d5d5SAlexander Hansen continue; 8642325d5d5SAlexander Hansen } 8652325d5d5SAlexander Hansen 8661cecc5deSJohnathan Mantey prc = POLLER_OK; 8671a0e03b4SJeremy Kerr 8681cecc5deSJohnathan Mantey /* process pending events... */ 8691cecc5deSJohnathan Mantey if (pollfd->revents) { 8701cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 871329a35f5SJeremy Kerr poller->data); 8722834c5b1SAndrew Jeffery if (prc == POLLER_EXIT) { 873329a35f5SJeremy Kerr rc = -1; 8742834c5b1SAndrew Jeffery } else if (prc == POLLER_REMOVE) { 875329a35f5SJeremy Kerr poller->remove = true; 876329a35f5SJeremy Kerr } 8772834c5b1SAndrew Jeffery } 878329a35f5SJeremy Kerr 8791cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 8801cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 8811cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 8821cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 8831cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 8841cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 8851cecc5deSJohnathan Mantey transmission. */ 8861cecc5deSJohnathan Mantey timerclear(&poller->timeout); 8871cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 8881cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 8891cecc5deSJohnathan Mantey rc = -1; 8901cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 8911cecc5deSJohnathan Mantey poller->remove = true; 8921cecc5deSJohnathan Mantey } 8931cecc5deSJohnathan Mantey } 8941cecc5deSJohnathan Mantey } 8951cecc5deSJohnathan Mantey 896329a35f5SJeremy Kerr /** 897329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 898329a35f5SJeremy Kerr * the array will have changed 899329a35f5SJeremy Kerr */ 900329a35f5SJeremy Kerr for (;;) { 901329a35f5SJeremy Kerr bool removed = false; 902329a35f5SJeremy Kerr 903329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 904329a35f5SJeremy Kerr poller = console->pollers[i]; 905329a35f5SJeremy Kerr if (poller->remove) { 90655c9712dSJeremy Kerr console_poller_unregister(console, poller); 907329a35f5SJeremy Kerr removed = true; 908329a35f5SJeremy Kerr break; 909329a35f5SJeremy Kerr } 910329a35f5SJeremy Kerr } 9112834c5b1SAndrew Jeffery if (!removed) { 912329a35f5SJeremy Kerr break; 9131a0e03b4SJeremy Kerr } 9142834c5b1SAndrew Jeffery } 9151a0e03b4SJeremy Kerr 9161a0e03b4SJeremy Kerr return rc; 9171a0e03b4SJeremy Kerr } 9181a0e03b4SJeremy Kerr 919769cee1aSJeremy Kerr static void sighandler(int signal) 920769cee1aSJeremy Kerr { 9212834c5b1SAndrew Jeffery if (signal == SIGINT) { 922553cb663SAndrew Jeffery sigint = 1; 923769cee1aSJeremy Kerr } 9242834c5b1SAndrew Jeffery } 925769cee1aSJeremy Kerr 926*312ecdc2SAlexander Hansen static int run_console_per_console(struct console *console, size_t buf_size, 927*312ecdc2SAlexander Hansen struct timeval *tv) 9281a0e03b4SJeremy Kerr { 929*312ecdc2SAlexander Hansen int rc; 930769cee1aSJeremy Kerr 931*312ecdc2SAlexander Hansen if (console->rb->size < buf_size) { 9326925740dSAlexander Hansen fprintf(stderr, "Ringbuffer size should be greater than %zuB\n", 933*312ecdc2SAlexander Hansen buf_size); 9346925740dSAlexander Hansen return -1; 9357f2bfb9bSMedicine Yeh } 9361764145dSJeremy Kerr 937769cee1aSJeremy Kerr if (sigint) { 938*312ecdc2SAlexander Hansen warnx("Received interrupt, exiting\n"); 9396925740dSAlexander Hansen return -1; 940769cee1aSJeremy Kerr } 941769cee1aSJeremy Kerr 942*312ecdc2SAlexander Hansen /* ... and then the pollers */ 943*312ecdc2SAlexander Hansen rc = call_pollers(console, tv); 944*312ecdc2SAlexander Hansen if (rc) { 945*312ecdc2SAlexander Hansen return -1; 946*312ecdc2SAlexander Hansen } 947*312ecdc2SAlexander Hansen 948*312ecdc2SAlexander Hansen return 0; 949*312ecdc2SAlexander Hansen } 950*312ecdc2SAlexander Hansen 951*312ecdc2SAlexander Hansen static int run_console_iteration(struct console_server *server) 952*312ecdc2SAlexander Hansen { 953*312ecdc2SAlexander Hansen struct timeval tv; 954*312ecdc2SAlexander Hansen uint8_t buf[4096]; 955*312ecdc2SAlexander Hansen long timeout; 956*312ecdc2SAlexander Hansen ssize_t rc; 957*312ecdc2SAlexander Hansen 9581cecc5deSJohnathan Mantey rc = get_current_time(&tv); 9591cecc5deSJohnathan Mantey if (rc) { 9601cecc5deSJohnathan Mantey warn("Failed to read current time"); 9616925740dSAlexander Hansen return -1; 9621cecc5deSJohnathan Mantey } 9631cecc5deSJohnathan Mantey 964*312ecdc2SAlexander Hansen timeout = get_poll_timeout(server->active, &tv); 9651cecc5deSJohnathan Mantey 966*312ecdc2SAlexander Hansen rc = poll(server->pollfds, server->capacity_pollfds, (int)timeout); 967*312ecdc2SAlexander Hansen 968*312ecdc2SAlexander Hansen if (sigint) { 969*312ecdc2SAlexander Hansen warnx("Received interrupt, exiting\n"); 970*312ecdc2SAlexander Hansen return -1; 971*312ecdc2SAlexander Hansen } 9721cecc5deSJohnathan Mantey 973d831f960SJeremy Kerr if (rc < 0) { 974769cee1aSJeremy Kerr if (errno == EINTR) { 9756925740dSAlexander Hansen return 0; 9760b7b0477SAndrew Jeffery } 977d831f960SJeremy Kerr warn("poll error"); 9786925740dSAlexander Hansen return -1; 979769cee1aSJeremy Kerr } 980d831f960SJeremy Kerr 981329a35f5SJeremy Kerr /* process internal fd first */ 982*312ecdc2SAlexander Hansen if (server->pollfds[server->tty_pollfd_index].revents) { 983*312ecdc2SAlexander Hansen rc = read(server->tty.fd, buf, sizeof(buf)); 984d831f960SJeremy Kerr if (rc <= 0) { 985d831f960SJeremy Kerr warn("Error reading from tty device"); 9866925740dSAlexander Hansen return -1; 987d831f960SJeremy Kerr } 988*312ecdc2SAlexander Hansen 989*312ecdc2SAlexander Hansen rc = ringbuffer_queue(server->active->rb, buf, rc); 9902834c5b1SAndrew Jeffery if (rc) { 9916925740dSAlexander Hansen return -1; 992d831f960SJeremy Kerr } 9932834c5b1SAndrew Jeffery } 994d831f960SJeremy Kerr 995*312ecdc2SAlexander Hansen // process dbus 996*312ecdc2SAlexander Hansen struct pollfd *dbus_pollfd = 997*312ecdc2SAlexander Hansen &(server->pollfds[server->dbus_pollfd_index]); 998*312ecdc2SAlexander Hansen if (dbus_pollfd->revents) { 999*312ecdc2SAlexander Hansen sd_bus_process(server->bus, NULL); 1000f9c8f6caSCheng C Yang } 1001f9c8f6caSCheng C Yang 1002*312ecdc2SAlexander Hansen for (size_t i = 0; i < server->n_consoles; i++) { 1003*312ecdc2SAlexander Hansen struct console *console = server->consoles[i]; 1004*312ecdc2SAlexander Hansen 1005*312ecdc2SAlexander Hansen rc = run_console_per_console(console, sizeof(buf), &tv); 1006*312ecdc2SAlexander Hansen if (rc != 0) { 10076925740dSAlexander Hansen return -1; 10086925740dSAlexander Hansen } 1009*312ecdc2SAlexander Hansen } 1010*312ecdc2SAlexander Hansen 10116925740dSAlexander Hansen return 0; 10126925740dSAlexander Hansen } 10136925740dSAlexander Hansen 1014*312ecdc2SAlexander Hansen int run_server(struct console_server *server) 10156925740dSAlexander Hansen { 1016*312ecdc2SAlexander Hansen sighandler_t sighandler_save; 10176925740dSAlexander Hansen ssize_t rc = 0; 10186925740dSAlexander Hansen 1019*312ecdc2SAlexander Hansen if (server->n_consoles == 0) { 1020*312ecdc2SAlexander Hansen warnx("no console configured for this server"); 1021*312ecdc2SAlexander Hansen return -1; 1022*312ecdc2SAlexander Hansen } 1023*312ecdc2SAlexander Hansen 1024*312ecdc2SAlexander Hansen sighandler_save = signal(SIGINT, sighandler); 10256925740dSAlexander Hansen for (;;) { 1026*312ecdc2SAlexander Hansen rc = run_console_iteration(server); 10276925740dSAlexander Hansen if (rc) { 1028769cee1aSJeremy Kerr break; 10291a0e03b4SJeremy Kerr } 10302834c5b1SAndrew Jeffery } 1031769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 1032769cee1aSJeremy Kerr 1033769cee1aSJeremy Kerr return rc ? -1 : 0; 10341a0e03b4SJeremy Kerr } 1035*312ecdc2SAlexander Hansen 1036d831f960SJeremy Kerr static const struct option options[] = { 1037d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 1038954be0fbSAndrew Jeffery { "console-id", required_argument, 0, 'i' }, 1039f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 1040d831f960SJeremy Kerr }; 1041d831f960SJeremy Kerr 1042*312ecdc2SAlexander Hansen static struct console *console_init(struct console_server *server, 1043*312ecdc2SAlexander Hansen struct config *config, 1044*312ecdc2SAlexander Hansen const char *console_id) 1045d831f960SJeremy Kerr { 10467f2bfb9bSMedicine Yeh size_t buffer_size = default_buffer_size; 1047*312ecdc2SAlexander Hansen const char *buffer_size_str = NULL; 1048*312ecdc2SAlexander Hansen int rc; 1049*312ecdc2SAlexander Hansen 1050*312ecdc2SAlexander Hansen struct console *console = calloc(1, sizeof(struct console)); 1051*312ecdc2SAlexander Hansen if (console == NULL) { 1052*312ecdc2SAlexander Hansen return NULL; 1053*312ecdc2SAlexander Hansen } 1054*312ecdc2SAlexander Hansen 1055*312ecdc2SAlexander Hansen console->server = server; 1056*312ecdc2SAlexander Hansen console->console_id = console_id; 1057*312ecdc2SAlexander Hansen 1058*312ecdc2SAlexander Hansen buffer_size_str = 1059*312ecdc2SAlexander Hansen config_get_section_value(config, console_id, "ringbuffer-size"); 1060*312ecdc2SAlexander Hansen 1061*312ecdc2SAlexander Hansen if (!buffer_size_str) { 1062*312ecdc2SAlexander Hansen buffer_size_str = config_get_value(config, "ringbuffer-size"); 1063*312ecdc2SAlexander Hansen } 1064*312ecdc2SAlexander Hansen 1065*312ecdc2SAlexander Hansen if (buffer_size_str) { 1066*312ecdc2SAlexander Hansen rc = config_parse_bytesize(buffer_size_str, &buffer_size); 1067*312ecdc2SAlexander Hansen if (rc) { 1068*312ecdc2SAlexander Hansen warn("Invalid ringbuffer-size. Default to %zukB", 1069*312ecdc2SAlexander Hansen buffer_size >> 10); 1070*312ecdc2SAlexander Hansen } 1071*312ecdc2SAlexander Hansen } 1072*312ecdc2SAlexander Hansen 1073*312ecdc2SAlexander Hansen console->rb = ringbuffer_init(buffer_size); 1074*312ecdc2SAlexander Hansen if (!console->rb) { 1075*312ecdc2SAlexander Hansen goto cleanup_console; 1076*312ecdc2SAlexander Hansen } 1077*312ecdc2SAlexander Hansen 1078*312ecdc2SAlexander Hansen if (set_socket_info(console, config, console_id)) { 1079*312ecdc2SAlexander Hansen warnx("set_socket_info failed"); 1080*312ecdc2SAlexander Hansen goto cleanup_rb; 1081*312ecdc2SAlexander Hansen } 1082*312ecdc2SAlexander Hansen 1083*312ecdc2SAlexander Hansen rc = dbus_init(console, config); 1084*312ecdc2SAlexander Hansen if (rc != 0) { 1085*312ecdc2SAlexander Hansen goto cleanup_rb; 1086*312ecdc2SAlexander Hansen } 1087*312ecdc2SAlexander Hansen 1088*312ecdc2SAlexander Hansen handlers_init(console, config); 1089*312ecdc2SAlexander Hansen 1090*312ecdc2SAlexander Hansen return console; 1091*312ecdc2SAlexander Hansen 1092*312ecdc2SAlexander Hansen cleanup_rb: 1093*312ecdc2SAlexander Hansen free(console->rb); 1094*312ecdc2SAlexander Hansen cleanup_console: 1095*312ecdc2SAlexander Hansen free(console); 1096*312ecdc2SAlexander Hansen 1097*312ecdc2SAlexander Hansen return NULL; 1098*312ecdc2SAlexander Hansen } 1099*312ecdc2SAlexander Hansen 1100*312ecdc2SAlexander Hansen static void console_fini(struct console *console) 1101*312ecdc2SAlexander Hansen { 1102*312ecdc2SAlexander Hansen handlers_fini(console); 1103*312ecdc2SAlexander Hansen ringbuffer_fini(console->rb); 1104*312ecdc2SAlexander Hansen free(console->pollers); 1105*312ecdc2SAlexander Hansen free(console); 1106*312ecdc2SAlexander Hansen } 1107*312ecdc2SAlexander Hansen 1108*312ecdc2SAlexander Hansen // 'opt_console_id' may be NULL 1109*312ecdc2SAlexander Hansen static int console_server_add_console(struct console_server *server, 1110*312ecdc2SAlexander Hansen struct config *config, 1111*312ecdc2SAlexander Hansen const char *opt_console_id) 1112*312ecdc2SAlexander Hansen { 1113*312ecdc2SAlexander Hansen const char *console_id; 1114*312ecdc2SAlexander Hansen struct console *console; 1115*312ecdc2SAlexander Hansen 1116*312ecdc2SAlexander Hansen console_id = config_resolve_console_id(config, opt_console_id); 1117*312ecdc2SAlexander Hansen 1118*312ecdc2SAlexander Hansen struct console **tmp = reallocarray(server->consoles, 1119*312ecdc2SAlexander Hansen server->n_consoles + 1, 1120*312ecdc2SAlexander Hansen sizeof(struct console *)); 1121*312ecdc2SAlexander Hansen if (tmp == NULL) { 1122*312ecdc2SAlexander Hansen warnx("could not realloc server->consoles"); 1123*312ecdc2SAlexander Hansen return -1; 1124*312ecdc2SAlexander Hansen } 1125*312ecdc2SAlexander Hansen server->consoles = tmp; 1126*312ecdc2SAlexander Hansen 1127*312ecdc2SAlexander Hansen console = console_init(server, config, console_id); 1128*312ecdc2SAlexander Hansen if (console == NULL) { 1129*312ecdc2SAlexander Hansen warnx("console_init failed"); 1130*312ecdc2SAlexander Hansen return -1; 1131*312ecdc2SAlexander Hansen } 1132*312ecdc2SAlexander Hansen 1133*312ecdc2SAlexander Hansen server->consoles[server->n_consoles++] = console; 1134*312ecdc2SAlexander Hansen 1135*312ecdc2SAlexander Hansen return 0; 1136*312ecdc2SAlexander Hansen } 1137*312ecdc2SAlexander Hansen 1138*312ecdc2SAlexander Hansen // returns NULL on error 1139*312ecdc2SAlexander Hansen static struct console * 1140*312ecdc2SAlexander Hansen console_server_add_consoles(struct console_server *server, 1141*312ecdc2SAlexander Hansen const char *arg_console_id) 1142*312ecdc2SAlexander Hansen { 1143*312ecdc2SAlexander Hansen int rc; 1144*312ecdc2SAlexander Hansen 1145*312ecdc2SAlexander Hansen const int nsections = config_count_sections(server->config); 1146*312ecdc2SAlexander Hansen if (nsections < 0) { 1147*312ecdc2SAlexander Hansen return NULL; 1148*312ecdc2SAlexander Hansen } 1149*312ecdc2SAlexander Hansen 1150*312ecdc2SAlexander Hansen if (nsections == 0) { 1151*312ecdc2SAlexander Hansen const char *console_id = arg_console_id; 1152*312ecdc2SAlexander Hansen 1153*312ecdc2SAlexander Hansen rc = console_server_add_console(server, server->config, 1154*312ecdc2SAlexander Hansen console_id); 1155*312ecdc2SAlexander Hansen if (rc != 0) { 1156*312ecdc2SAlexander Hansen return NULL; 1157*312ecdc2SAlexander Hansen } 1158*312ecdc2SAlexander Hansen } 1159*312ecdc2SAlexander Hansen 1160*312ecdc2SAlexander Hansen for (int i = 0; i < nsections; i++) { 1161*312ecdc2SAlexander Hansen const char *console_id = 1162*312ecdc2SAlexander Hansen config_get_section_name(server->config, i); 1163*312ecdc2SAlexander Hansen 1164*312ecdc2SAlexander Hansen if (console_id == NULL) { 1165*312ecdc2SAlexander Hansen warnx("no console id provided\n"); 1166*312ecdc2SAlexander Hansen return NULL; 1167*312ecdc2SAlexander Hansen } 1168*312ecdc2SAlexander Hansen 1169*312ecdc2SAlexander Hansen rc = console_server_add_console(server, server->config, 1170*312ecdc2SAlexander Hansen console_id); 1171*312ecdc2SAlexander Hansen if (rc != 0) { 1172*312ecdc2SAlexander Hansen return NULL; 1173*312ecdc2SAlexander Hansen } 1174*312ecdc2SAlexander Hansen } 1175*312ecdc2SAlexander Hansen 1176*312ecdc2SAlexander Hansen const char *initially_active = 1177*312ecdc2SAlexander Hansen config_get_value(server->config, "active-console"); 1178*312ecdc2SAlexander Hansen if (!initially_active) { 1179*312ecdc2SAlexander Hansen return server->consoles[0]; 1180*312ecdc2SAlexander Hansen } 1181*312ecdc2SAlexander Hansen 1182*312ecdc2SAlexander Hansen printf("setting console-id '%s' as the initially active console\n", 1183*312ecdc2SAlexander Hansen initially_active); 1184*312ecdc2SAlexander Hansen 1185*312ecdc2SAlexander Hansen for (size_t i = 0; i < server->n_consoles; i++) { 1186*312ecdc2SAlexander Hansen struct console *console = server->consoles[i]; 1187*312ecdc2SAlexander Hansen 1188*312ecdc2SAlexander Hansen if (strcmp(console->console_id, initially_active) == 0) { 1189*312ecdc2SAlexander Hansen return console; 1190*312ecdc2SAlexander Hansen } 1191*312ecdc2SAlexander Hansen } 1192*312ecdc2SAlexander Hansen 1193*312ecdc2SAlexander Hansen warnx("'active-console' '%s' not found among console ids\n", 1194*312ecdc2SAlexander Hansen initially_active); 1195*312ecdc2SAlexander Hansen 1196*312ecdc2SAlexander Hansen return NULL; 1197*312ecdc2SAlexander Hansen } 1198*312ecdc2SAlexander Hansen 1199*312ecdc2SAlexander Hansen int console_server_init(struct console_server *server, 1200*312ecdc2SAlexander Hansen const char *config_filename, 1201*312ecdc2SAlexander Hansen const char *config_tty_kname, const char *console_id) 1202*312ecdc2SAlexander Hansen { 1203*312ecdc2SAlexander Hansen int rc; 1204*312ecdc2SAlexander Hansen memset(server, 0, sizeof(struct console_server)); 1205*312ecdc2SAlexander Hansen 1206*312ecdc2SAlexander Hansen server->tty_pollfd_index = -1; 1207*312ecdc2SAlexander Hansen 1208*312ecdc2SAlexander Hansen server->config = config_init(config_filename); 1209*312ecdc2SAlexander Hansen if (server->config == NULL) { 1210*312ecdc2SAlexander Hansen return -1; 1211*312ecdc2SAlexander Hansen } 1212*312ecdc2SAlexander Hansen 1213*312ecdc2SAlexander Hansen uart_routing_init(server->config); 1214*312ecdc2SAlexander Hansen 1215*312ecdc2SAlexander Hansen rc = tty_init(server, server->config, config_tty_kname); 1216*312ecdc2SAlexander Hansen if (rc != 0) { 1217*312ecdc2SAlexander Hansen warnx("error during tty_init, exiting.\n"); 1218*312ecdc2SAlexander Hansen return -1; 1219*312ecdc2SAlexander Hansen } 1220*312ecdc2SAlexander Hansen 1221*312ecdc2SAlexander Hansen rc = dbus_server_init(server); 1222*312ecdc2SAlexander Hansen if (rc != 0) { 1223*312ecdc2SAlexander Hansen warnx("error during dbus init for console server"); 1224*312ecdc2SAlexander Hansen return -1; 1225*312ecdc2SAlexander Hansen } 1226*312ecdc2SAlexander Hansen 1227*312ecdc2SAlexander Hansen server->active = console_server_add_consoles(server, console_id); 1228*312ecdc2SAlexander Hansen if (server->active == NULL) { 1229*312ecdc2SAlexander Hansen return -1; 1230*312ecdc2SAlexander Hansen } 1231*312ecdc2SAlexander Hansen 1232*312ecdc2SAlexander Hansen return 0; 1233*312ecdc2SAlexander Hansen } 1234*312ecdc2SAlexander Hansen 1235*312ecdc2SAlexander Hansen void console_server_fini(struct console_server *server) 1236*312ecdc2SAlexander Hansen { 1237*312ecdc2SAlexander Hansen for (size_t i = 0; i < server->n_consoles; i++) { 1238*312ecdc2SAlexander Hansen console_fini(server->consoles[i]); 1239*312ecdc2SAlexander Hansen } 1240*312ecdc2SAlexander Hansen 1241*312ecdc2SAlexander Hansen free(server->consoles); 1242*312ecdc2SAlexander Hansen dbus_server_fini(server); 1243*312ecdc2SAlexander Hansen tty_fini(server); 1244*312ecdc2SAlexander Hansen free(server->pollfds); 1245*312ecdc2SAlexander Hansen config_fini(server->config); 1246*312ecdc2SAlexander Hansen } 1247*312ecdc2SAlexander Hansen 1248*312ecdc2SAlexander Hansen int main(int argc, char **argv) 1249*312ecdc2SAlexander Hansen { 1250d66195c1SJeremy Kerr const char *config_filename = NULL; 12516221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 1252954be0fbSAndrew Jeffery const char *console_id = NULL; 1253c2b0d8c7SAlexander Hansen struct console_server server = { 0 }; 1254*312ecdc2SAlexander Hansen int rc = 0; 1255d831f960SJeremy Kerr 1256d831f960SJeremy Kerr for (;;) { 1257b70f8713SAndrew Jeffery int c; 1258b70f8713SAndrew Jeffery int idx; 1259d831f960SJeremy Kerr 1260954be0fbSAndrew Jeffery c = getopt_long(argc, argv, "c:i:", options, &idx); 12612834c5b1SAndrew Jeffery if (c == -1) { 1262d831f960SJeremy Kerr break; 12632834c5b1SAndrew Jeffery } 1264d831f960SJeremy Kerr 1265d831f960SJeremy Kerr switch (c) { 1266d66195c1SJeremy Kerr case 'c': 1267d66195c1SJeremy Kerr config_filename = optarg; 1268d831f960SJeremy Kerr break; 1269954be0fbSAndrew Jeffery case 'i': 1270954be0fbSAndrew Jeffery console_id = optarg; 1271954be0fbSAndrew Jeffery break; 1272d831f960SJeremy Kerr case 'h': 1273d831f960SJeremy Kerr case '?': 1274d831f960SJeremy Kerr usage(argv[0]); 1275d66195c1SJeremy Kerr return EXIT_SUCCESS; 1276d831f960SJeremy Kerr } 1277d831f960SJeremy Kerr } 1278d831f960SJeremy Kerr 12792834c5b1SAndrew Jeffery if (optind < argc) { 12806221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 1281*312ecdc2SAlexander Hansen } else { 1282*312ecdc2SAlexander Hansen errx(EXIT_FAILURE, "no tty device path has been provided\n"); 12832834c5b1SAndrew Jeffery } 12846221ce94SVishwanatha Subbanna 1285*312ecdc2SAlexander Hansen rc = console_server_init(&server, config_filename, config_tty_kname, 1286*312ecdc2SAlexander Hansen console_id); 1287*312ecdc2SAlexander Hansen 1288*312ecdc2SAlexander Hansen if (rc == 0) { 1289*312ecdc2SAlexander Hansen rc = run_server(&server); 129028a1761aSAndrew Jeffery } 12917f2bfb9bSMedicine Yeh 1292*312ecdc2SAlexander Hansen console_server_fini(&server); 129328a1761aSAndrew Jeffery 1294d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 1295d831f960SJeremy Kerr } 1296