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> 3117217845SJeremy Kerr #include <limits.h> 321cecc5deSJohnathan Mantey #include <time.h> 3354e9569dSJeremy Kerr #include <termios.h> 34d831f960SJeremy Kerr 35d831f960SJeremy Kerr #include <sys/types.h> 361cecc5deSJohnathan Mantey #include <sys/time.h> 37b14ca19cSNinad Palsule #include <sys/socket.h> 3887e344cdSJoel Stanley #include <poll.h> 39d831f960SJeremy Kerr 401a0e03b4SJeremy Kerr #include "console-server.h" 41d831f960SJeremy Kerr 4230ea6385SAndrew Jeffery #define DEV_PTS_PATH "/dev/pts" 4330ea6385SAndrew Jeffery 44f733c85aSJeremy Kerr /* size of the shared backlog ringbuffer */ 455db8c792SAndrew Jeffery const size_t buffer_size = 128ul * 1024ul; 46f733c85aSJeremy Kerr 47769cee1aSJeremy Kerr /* state shared with the signal handler */ 48769cee1aSJeremy Kerr static bool sigint; 49329a35f5SJeremy Kerr 50d831f960SJeremy Kerr static void usage(const char *progname) 51d831f960SJeremy Kerr { 52d831f960SJeremy Kerr fprintf(stderr, 536221ce94SVishwanatha Subbanna "usage: %s [options] <DEVICE>\n" 54d831f960SJeremy Kerr "\n" 55d831f960SJeremy Kerr "Options:\n" 56954be0fbSAndrew Jeffery " --config <FILE>\tUse FILE for configuration\n" 57954be0fbSAndrew Jeffery " --console-id <NAME>\tUse NAME in the UNIX domain socket address\n" 58d831f960SJeremy Kerr "", 59d831f960SJeremy Kerr progname); 60d831f960SJeremy Kerr } 61d831f960SJeremy Kerr 6230ea6385SAndrew Jeffery /* populates console->tty.dev and console->tty.sysfs_devnode, using the tty kernel name */ 631a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 6417217845SJeremy Kerr { 65d3cb9c22SAndrew Jeffery char *tty_class_device_link = NULL; 66d3cb9c22SAndrew Jeffery char *tty_path_input_real = NULL; 67d3cb9c22SAndrew Jeffery char *tty_device_tty_dir = NULL; 6830ea6385SAndrew Jeffery char *tty_vuart_lpc_addr = NULL; 69d3cb9c22SAndrew Jeffery char *tty_device_reldir = NULL; 7030ea6385SAndrew Jeffery char *tty_sysfs_devnode = NULL; 71d3cb9c22SAndrew Jeffery char *tty_kname_real = NULL; 7230ea6385SAndrew Jeffery char *tty_path_input = NULL; 7317217845SJeremy Kerr int rc; 7417217845SJeremy Kerr 7530ea6385SAndrew Jeffery console->tty.type = TTY_DEVICE_UNDEFINED; 7630ea6385SAndrew Jeffery 7730ea6385SAndrew Jeffery assert(console->tty.kname); 7830ea6385SAndrew Jeffery if (!strlen(console->tty.kname)) { 7930ea6385SAndrew Jeffery warnx("TTY kname must not be empty"); 8030ea6385SAndrew Jeffery rc = -1; 8130ea6385SAndrew Jeffery goto out_free; 822834c5b1SAndrew Jeffery } 8317217845SJeremy Kerr 8430ea6385SAndrew Jeffery if (console->tty.kname[0] == '/') { 8530ea6385SAndrew Jeffery tty_path_input = strdup(console->tty.kname); 8630ea6385SAndrew Jeffery if (!tty_path_input) { 8730ea6385SAndrew Jeffery rc = -1; 8830ea6385SAndrew Jeffery goto out_free; 8930ea6385SAndrew Jeffery } 9030ea6385SAndrew Jeffery } else { 9130ea6385SAndrew Jeffery rc = asprintf(&tty_path_input, "/dev/%s", console->tty.kname); 9230ea6385SAndrew Jeffery if (rc < 0) { 9330ea6385SAndrew Jeffery goto out_free; 9430ea6385SAndrew Jeffery } 9530ea6385SAndrew Jeffery } 9630ea6385SAndrew Jeffery 9730ea6385SAndrew Jeffery /* udev may rename the tty name with a symbol link, try to resolve */ 9845ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 9945ad7676SYi Li if (!tty_path_input_real) { 10030ea6385SAndrew Jeffery warn("Can't find realpath for %s", tty_path_input); 10115792aa7SAndrew Jeffery rc = -1; 10245ad7676SYi Li goto out_free; 10345ad7676SYi Li } 10445ad7676SYi Li 10530ea6385SAndrew Jeffery /* 10630ea6385SAndrew Jeffery * Allow hooking obmc-console-server up to PTYs for testing 10730ea6385SAndrew Jeffery * 10830ea6385SAndrew Jeffery * https://amboar.github.io/notes/2023/05/02/testing-obmc-console-with-socat.html 10930ea6385SAndrew Jeffery */ 11030ea6385SAndrew Jeffery if (!strncmp(DEV_PTS_PATH, tty_path_input_real, strlen(DEV_PTS_PATH))) { 11130ea6385SAndrew Jeffery console->tty.type = TTY_DEVICE_PTY; 11230ea6385SAndrew Jeffery console->tty.dev = strdup(console->tty.kname); 11330ea6385SAndrew Jeffery rc = console->tty.dev ? 0 : -1; 11430ea6385SAndrew Jeffery goto out_free; 11530ea6385SAndrew Jeffery } 11630ea6385SAndrew Jeffery 11745ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 11845ad7676SYi Li if (!tty_kname_real) { 11930ea6385SAndrew Jeffery warn("Can't find real name for %s", console->tty.kname); 12015792aa7SAndrew Jeffery rc = -1; 12145ad7676SYi Li goto out_free; 12245ad7676SYi Li } 12345ad7676SYi Li 124a72711afSAndrew Jeffery rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s", 125a72711afSAndrew Jeffery tty_kname_real); 1262834c5b1SAndrew Jeffery if (rc < 0) { 12745ad7676SYi Li goto out_free; 1282834c5b1SAndrew Jeffery } 12945ad7676SYi Li 13017217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 13145ad7676SYi Li if (!tty_device_tty_dir) { 13245ad7676SYi Li warn("Can't query sysfs for device %s", tty_kname_real); 13315792aa7SAndrew Jeffery rc = -1; 13417217845SJeremy Kerr goto out_free; 13517217845SJeremy Kerr } 13617217845SJeremy Kerr 13717217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 1382834c5b1SAndrew Jeffery if (rc < 0) { 13917217845SJeremy Kerr goto out_free; 1402834c5b1SAndrew Jeffery } 14117217845SJeremy Kerr 14230ea6385SAndrew Jeffery tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 14330ea6385SAndrew Jeffery if (!tty_sysfs_devnode) { 14445ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 1452834c5b1SAndrew Jeffery } 14617217845SJeremy Kerr 14730ea6385SAndrew Jeffery rc = asprintf(&console->tty.dev, "/dev/%s", tty_kname_real); 1482834c5b1SAndrew Jeffery if (rc < 0) { 14917217845SJeremy Kerr goto out_free; 1502834c5b1SAndrew Jeffery } 15117217845SJeremy Kerr 15230ea6385SAndrew Jeffery /* Arbitrarily pick an attribute to differentiate UART vs VUART */ 15330ea6385SAndrew Jeffery rc = asprintf(&tty_vuart_lpc_addr, "%s/lpc_addr", tty_sysfs_devnode); 15430ea6385SAndrew Jeffery if (rc < 0) { 15530ea6385SAndrew Jeffery goto out_free; 15630ea6385SAndrew Jeffery } 15730ea6385SAndrew Jeffery 15830ea6385SAndrew Jeffery rc = access(tty_vuart_lpc_addr, F_OK); 15930ea6385SAndrew Jeffery console->tty.type = (!rc) ? TTY_DEVICE_VUART : TTY_DEVICE_UART; 16030ea6385SAndrew Jeffery 16117217845SJeremy Kerr rc = 0; 16217217845SJeremy Kerr 16317217845SJeremy Kerr out_free: 16430ea6385SAndrew Jeffery free(tty_vuart_lpc_addr); 16517217845SJeremy Kerr free(tty_class_device_link); 16617217845SJeremy Kerr free(tty_device_tty_dir); 16717217845SJeremy Kerr free(tty_device_reldir); 16845ad7676SYi Li free(tty_path_input); 16945ad7676SYi Li free(tty_path_input_real); 17017217845SJeremy Kerr return rc; 17117217845SJeremy Kerr } 17217217845SJeremy Kerr 1731a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 174957818b4SJeremy Kerr int value) 175957818b4SJeremy Kerr { 176957818b4SJeremy Kerr char *path; 177957818b4SJeremy Kerr FILE *fp; 178957818b4SJeremy Kerr int rc; 179957818b4SJeremy Kerr 18030ea6385SAndrew Jeffery assert(console->tty.type == TTY_DEVICE_VUART); 18130ea6385SAndrew Jeffery 18230ea6385SAndrew Jeffery if (!console->tty.vuart.sysfs_devnode) { 18330ea6385SAndrew Jeffery return -1; 18430ea6385SAndrew Jeffery } 18530ea6385SAndrew Jeffery 18630ea6385SAndrew Jeffery rc = asprintf(&path, "%s/%s", console->tty.vuart.sysfs_devnode, name); 1872834c5b1SAndrew Jeffery if (rc < 0) { 188957818b4SJeremy Kerr return -1; 1892834c5b1SAndrew Jeffery } 190957818b4SJeremy Kerr 191957818b4SJeremy Kerr fp = fopen(path, "w"); 192957818b4SJeremy Kerr if (!fp) { 193a72711afSAndrew Jeffery warn("Can't access attribute %s on device %s", name, 19430ea6385SAndrew Jeffery console->tty.kname); 195957818b4SJeremy Kerr rc = -1; 196957818b4SJeremy Kerr goto out_free; 197957818b4SJeremy Kerr } 198957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 199957818b4SJeremy Kerr 200957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 2012834c5b1SAndrew Jeffery if (rc < 0) { 202a72711afSAndrew Jeffery warn("Error writing to %s attribute of device %s", name, 20330ea6385SAndrew Jeffery console->tty.kname); 2042834c5b1SAndrew Jeffery } 205957818b4SJeremy Kerr fclose(fp); 206957818b4SJeremy Kerr 207957818b4SJeremy Kerr out_free: 208957818b4SJeremy Kerr free(path); 209957818b4SJeremy Kerr return rc; 210957818b4SJeremy Kerr } 211957818b4SJeremy Kerr 212d831f960SJeremy Kerr /** 213c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 21454e9569dSJeremy Kerr */ 215e258e51fSNinad Palsule void tty_init_termios(struct console *console) 21654e9569dSJeremy Kerr { 21754e9569dSJeremy Kerr struct termios termios; 21854e9569dSJeremy Kerr int rc; 21954e9569dSJeremy Kerr 22030ea6385SAndrew Jeffery rc = tcgetattr(console->tty.fd, &termios); 22154e9569dSJeremy Kerr if (rc) { 22254e9569dSJeremy Kerr warn("Can't read tty termios"); 22354e9569dSJeremy Kerr return; 22454e9569dSJeremy Kerr } 22554e9569dSJeremy Kerr 22630ea6385SAndrew Jeffery if (console->tty.type == TTY_DEVICE_UART && console->tty.uart.baud) { 22730ea6385SAndrew Jeffery if (cfsetspeed(&termios, console->tty.uart.baud) < 0) { 22830ea6385SAndrew Jeffery warn("Couldn't set speeds for %s", console->tty.kname); 229c7fbcd48SBenjamin Fair } 2302834c5b1SAndrew Jeffery } 231c7fbcd48SBenjamin Fair 232c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 233c7fbcd48SBenjamin Fair * the underlying terminal input/output. 234c7fbcd48SBenjamin Fair */ 23554e9569dSJeremy Kerr cfmakeraw(&termios); 236c7fbcd48SBenjamin Fair 23730ea6385SAndrew Jeffery rc = tcsetattr(console->tty.fd, TCSANOW, &termios); 2382834c5b1SAndrew Jeffery if (rc) { 23930ea6385SAndrew Jeffery warn("Can't set terminal options for %s", console->tty.kname); 24054e9569dSJeremy Kerr } 2412834c5b1SAndrew Jeffery } 24254e9569dSJeremy Kerr 24354e9569dSJeremy Kerr /** 244d831f960SJeremy Kerr * Open and initialise the serial device 245d831f960SJeremy Kerr */ 24630ea6385SAndrew Jeffery static void tty_init_vuart_io(struct console *console) 247d831f960SJeremy Kerr { 24830ea6385SAndrew Jeffery assert(console->tty.type == TTY_DEVICE_VUART); 24930ea6385SAndrew Jeffery 25030ea6385SAndrew Jeffery if (console->tty.vuart.sirq) { 25130ea6385SAndrew Jeffery tty_set_sysfs_attr(console, "sirq", console->tty.vuart.sirq); 2522834c5b1SAndrew Jeffery } 253957818b4SJeremy Kerr 25430ea6385SAndrew Jeffery if (console->tty.vuart.lpc_addr) { 25530ea6385SAndrew Jeffery tty_set_sysfs_attr(console, "lpc_address", 25630ea6385SAndrew Jeffery console->tty.vuart.lpc_addr); 25730ea6385SAndrew Jeffery } 25830ea6385SAndrew Jeffery } 25930ea6385SAndrew Jeffery 26030ea6385SAndrew Jeffery static int tty_init_io(struct console *console) 26130ea6385SAndrew Jeffery { 26230ea6385SAndrew Jeffery console->tty.fd = open(console->tty.dev, O_RDWR); 26330ea6385SAndrew Jeffery if (console->tty.fd <= 0) { 26430ea6385SAndrew Jeffery warn("Can't open tty %s", console->tty.dev); 265d831f960SJeremy Kerr return -1; 266d831f960SJeremy Kerr } 267d831f960SJeremy Kerr 268d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 269d831f960SJeremy Kerr * we detect larger amounts of data 270d831f960SJeremy Kerr */ 27130ea6385SAndrew Jeffery fcntl(console->tty.fd, F_SETFL, FNDELAY); 272d831f960SJeremy Kerr 27354e9569dSJeremy Kerr tty_init_termios(console); 27454e9569dSJeremy Kerr 27530ea6385SAndrew Jeffery console->pollfds[console->n_pollers].fd = console->tty.fd; 276329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 277329a35f5SJeremy Kerr 278d831f960SJeremy Kerr return 0; 279d831f960SJeremy Kerr } 280d831f960SJeremy Kerr 28130ea6385SAndrew Jeffery static int tty_init_vuart(struct console *console, struct config *config) 282d66195c1SJeremy Kerr { 283fd883a88SAndrew Jeffery unsigned long parsed; 284d66195c1SJeremy Kerr const char *val; 285d66195c1SJeremy Kerr char *endp; 28630ea6385SAndrew Jeffery 28730ea6385SAndrew Jeffery assert(console->tty.type == TTY_DEVICE_VUART); 288d66195c1SJeremy Kerr 289d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 290d66195c1SJeremy Kerr if (val) { 291fd883a88SAndrew Jeffery errno = 0; 292fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 293fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 294fd883a88SAndrew Jeffery warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'", 295fd883a88SAndrew Jeffery val); 296fd883a88SAndrew Jeffery return -1; 297fd883a88SAndrew Jeffery } 298fd883a88SAndrew Jeffery 299fd883a88SAndrew Jeffery if (parsed > UINT16_MAX) { 300fd883a88SAndrew Jeffery warn("Invalid LPC address '%s'", val); 301fd883a88SAndrew Jeffery return -1; 302fd883a88SAndrew Jeffery } 303fd883a88SAndrew Jeffery 30430ea6385SAndrew Jeffery console->tty.vuart.lpc_addr = (uint16_t)parsed; 305d66195c1SJeremy Kerr if (endp == optarg) { 306d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 307d66195c1SJeremy Kerr return -1; 308d66195c1SJeremy Kerr } 309d66195c1SJeremy Kerr } 310d66195c1SJeremy Kerr 311d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 312d66195c1SJeremy Kerr if (val) { 313fd883a88SAndrew Jeffery errno = 0; 314fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 315fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 316fd883a88SAndrew Jeffery warn("Cannot interpret 'sirq' value as an unsigned long: '%s'", 317fd883a88SAndrew Jeffery val); 318fd883a88SAndrew Jeffery } 319fd883a88SAndrew Jeffery 3202834c5b1SAndrew Jeffery if (parsed > 16) { 321fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 3222834c5b1SAndrew Jeffery } 323fd883a88SAndrew Jeffery 32430ea6385SAndrew Jeffery console->tty.vuart.sirq = (int)parsed; 3252834c5b1SAndrew Jeffery if (endp == optarg) { 326d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 327d66195c1SJeremy Kerr } 3282834c5b1SAndrew Jeffery } 329d66195c1SJeremy Kerr 33030ea6385SAndrew Jeffery return 0; 3312834c5b1SAndrew Jeffery } 332c7fbcd48SBenjamin Fair 33330ea6385SAndrew Jeffery static int tty_init(struct console *console, struct config *config, 33430ea6385SAndrew Jeffery const char *tty_arg) 33530ea6385SAndrew Jeffery { 33630ea6385SAndrew Jeffery const char *val; 33730ea6385SAndrew Jeffery int rc; 33830ea6385SAndrew Jeffery 339d769eecfSAndrew Jeffery if (tty_arg) { 34030ea6385SAndrew Jeffery console->tty.kname = tty_arg; 341d769eecfSAndrew Jeffery } else if ((val = config_get_value(config, "upstream-tty"))) { 34230ea6385SAndrew Jeffery console->tty.kname = val; 343d769eecfSAndrew Jeffery } else { 344d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 345d66195c1SJeremy Kerr return -1; 346d66195c1SJeremy Kerr } 347d66195c1SJeremy Kerr 348d66195c1SJeremy Kerr rc = tty_find_device(console); 3492834c5b1SAndrew Jeffery if (rc) { 350d66195c1SJeremy Kerr return rc; 3512834c5b1SAndrew Jeffery } 352d66195c1SJeremy Kerr 35330ea6385SAndrew Jeffery switch (console->tty.type) { 35430ea6385SAndrew Jeffery case TTY_DEVICE_VUART: 35530ea6385SAndrew Jeffery rc = tty_init_vuart(console, config); 35630ea6385SAndrew Jeffery if (rc) { 357d66195c1SJeremy Kerr return rc; 358d66195c1SJeremy Kerr } 359d66195c1SJeremy Kerr 36030ea6385SAndrew Jeffery tty_init_vuart_io(console); 36130ea6385SAndrew Jeffery break; 36230ea6385SAndrew Jeffery case TTY_DEVICE_UART: 36330ea6385SAndrew Jeffery val = config_get_value(config, "baud"); 36430ea6385SAndrew Jeffery if (val) { 36530ea6385SAndrew Jeffery if (config_parse_baud(&console->tty.uart.baud, val)) { 36630ea6385SAndrew Jeffery warnx("Invalid baud rate: '%s'", val); 36730ea6385SAndrew Jeffery } 36830ea6385SAndrew Jeffery } 36930ea6385SAndrew Jeffery break; 37030ea6385SAndrew Jeffery case TTY_DEVICE_PTY: 37130ea6385SAndrew Jeffery break; 37230ea6385SAndrew Jeffery case TTY_DEVICE_UNDEFINED: 37330ea6385SAndrew Jeffery default: 37430ea6385SAndrew Jeffery warnx("Cannot configure unrecognised TTY device"); 37530ea6385SAndrew Jeffery return -1; 37630ea6385SAndrew Jeffery } 37730ea6385SAndrew Jeffery 37830ea6385SAndrew Jeffery return tty_init_io(console); 37930ea6385SAndrew Jeffery } 38030ea6385SAndrew Jeffery 38130ea6385SAndrew Jeffery static void tty_fini(struct console *console) 38230ea6385SAndrew Jeffery { 38330ea6385SAndrew Jeffery if (console->tty.type == TTY_DEVICE_VUART) { 38430ea6385SAndrew Jeffery free(console->tty.vuart.sysfs_devnode); 38530ea6385SAndrew Jeffery } 38630ea6385SAndrew Jeffery free(console->tty.dev); 38730ea6385SAndrew Jeffery } 38830ea6385SAndrew Jeffery 3891a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 390d831f960SJeremy Kerr { 39130ea6385SAndrew Jeffery return write_buf_to_fd(console->tty.fd, data, len); 392d831f960SJeremy Kerr } 393d831f960SJeremy Kerr 394b14ca19cSNinad Palsule /* Read console if from config and prepare a socket name */ 395954be0fbSAndrew Jeffery static int set_socket_info(struct console *console, struct config *config, 396954be0fbSAndrew Jeffery const char *console_id) 397b14ca19cSNinad Palsule { 398954be0fbSAndrew Jeffery const char *resolved_id; 399b14ca19cSNinad Palsule ssize_t len; 400b14ca19cSNinad Palsule 401954be0fbSAndrew Jeffery if (console_id) { 402954be0fbSAndrew Jeffery resolved_id = console_id; 403954be0fbSAndrew Jeffery } else { 404954be0fbSAndrew Jeffery resolved_id = config_get_value(config, "console-id"); 4059a8f30ecSAndrew Jeffery 4069a8f30ecSAndrew Jeffery /* socket-id is deprecated */ 407954be0fbSAndrew Jeffery if (!resolved_id) { 408954be0fbSAndrew Jeffery resolved_id = config_get_value(config, "socket-id"); 409954be0fbSAndrew Jeffery } 4109a8f30ecSAndrew Jeffery } 4119a8f30ecSAndrew Jeffery 412954be0fbSAndrew Jeffery console->console_id = resolved_id; 413954be0fbSAndrew Jeffery 414b14ca19cSNinad Palsule /* Get the socket name/path */ 415954be0fbSAndrew Jeffery len = console_socket_path(console->socket_name, resolved_id); 416b14ca19cSNinad Palsule if (len < 0) { 417b14ca19cSNinad Palsule warn("Failed to set socket path: %s", strerror(errno)); 418b14ca19cSNinad Palsule return EXIT_FAILURE; 419b14ca19cSNinad Palsule } 420b14ca19cSNinad Palsule 421b14ca19cSNinad Palsule /* Socket name is not a null terminated string hence save the length */ 422b14ca19cSNinad Palsule console->socket_name_len = len; 423b14ca19cSNinad Palsule 424b14ca19cSNinad Palsule return 0; 425b14ca19cSNinad Palsule } 426b14ca19cSNinad Palsule 427d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 428d831f960SJeremy Kerr { 429b70f8713SAndrew Jeffery /* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 430b70f8713SAndrew Jeffery extern struct handler *__start_handlers; 431b70f8713SAndrew Jeffery extern struct handler *__stop_handlers; 432b70f8713SAndrew Jeffery /* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 4331a0e03b4SJeremy Kerr struct handler *handler; 434b70f8713SAndrew Jeffery int i; 435b70f8713SAndrew Jeffery int rc; 436d831f960SJeremy Kerr 4371a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4381a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 439d831f960SJeremy Kerr 4405c359cc6SAndrew Jeffery printf("%ld handler%s\n", console->n_handlers, 4411a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 442d831f960SJeremy Kerr 4431a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4441a0e03b4SJeremy Kerr handler = console->handlers[i]; 4451a0e03b4SJeremy Kerr 446021b91f0SJeremy Kerr rc = 0; 4472834c5b1SAndrew Jeffery if (handler->init) { 448021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 4492834c5b1SAndrew Jeffery } 450021b91f0SJeremy Kerr 451021b91f0SJeremy Kerr handler->active = rc == 0; 452021b91f0SJeremy Kerr 453021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 454021b91f0SJeremy Kerr handler->active ? "" : "in"); 455d831f960SJeremy Kerr } 456d831f960SJeremy Kerr } 457d831f960SJeremy Kerr 4581a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 459d831f960SJeremy Kerr { 4601a0e03b4SJeremy Kerr struct handler *handler; 4611a0e03b4SJeremy Kerr int i; 4621a0e03b4SJeremy Kerr 4631a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4641a0e03b4SJeremy Kerr handler = console->handlers[i]; 4652834c5b1SAndrew Jeffery if (handler->fini && handler->active) { 4661a0e03b4SJeremy Kerr handler->fini(handler); 4671a0e03b4SJeremy Kerr } 468d831f960SJeremy Kerr } 4692834c5b1SAndrew Jeffery } 470d831f960SJeremy Kerr 4711cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 4721cecc5deSJohnathan Mantey { 4731cecc5deSJohnathan Mantey struct timespec t; 4741cecc5deSJohnathan Mantey int rc; 4751cecc5deSJohnathan Mantey 4761cecc5deSJohnathan Mantey /* 4771cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 4781cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 4791cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 4801cecc5deSJohnathan Mantey */ 4811cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 4822834c5b1SAndrew Jeffery if (rc) { 4831cecc5deSJohnathan Mantey return rc; 4842834c5b1SAndrew Jeffery } 4851cecc5deSJohnathan Mantey 4861cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 4871cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 4881cecc5deSJohnathan Mantey 4891cecc5deSJohnathan Mantey return 0; 4901cecc5deSJohnathan Mantey } 4911cecc5deSJohnathan Mantey 492a72711afSAndrew Jeffery struct ringbuffer_consumer * 493a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console, 494f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 495d831f960SJeremy Kerr { 496f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 497d831f960SJeremy Kerr } 498d831f960SJeremy Kerr 49955c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 500a72711afSAndrew Jeffery struct handler *handler, 501a72711afSAndrew Jeffery poller_event_fn_t poller_fn, 5021cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 5031cecc5deSJohnathan Mantey int events, void *data) 504d831f960SJeremy Kerr { 505329a35f5SJeremy Kerr struct poller *poller; 5065c359cc6SAndrew Jeffery long n; 507329a35f5SJeremy Kerr 508329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 509329a35f5SJeremy Kerr poller->remove = false; 510329a35f5SJeremy Kerr poller->handler = handler; 5111cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5121cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 513329a35f5SJeremy Kerr poller->data = data; 514329a35f5SJeremy Kerr 515329a35f5SJeremy Kerr /* add one to our pollers array */ 516329a35f5SJeremy Kerr n = console->n_pollers++; 51791b52175SAndrew Jeffery /* 51891b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 51991b52175SAndrew Jeffery * pointer type. 52091b52175SAndrew Jeffery */ 52191b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 52291b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 52391b52175SAndrew Jeffery sizeof(*console->pollers)); 52491b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 525329a35f5SJeremy Kerr 526329a35f5SJeremy Kerr console->pollers[n] = poller; 527329a35f5SJeremy Kerr 528329a35f5SJeremy Kerr /* increase pollfds array too */ 529*4e44c790SAndrew Jeffery console->pollfds = reallocarray( 530*4e44c790SAndrew Jeffery console->pollfds, (MAX_INTERNAL_POLLFD + console->n_pollers), 53191b52175SAndrew Jeffery sizeof(*console->pollfds)); 532329a35f5SJeremy Kerr 533329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 534a72711afSAndrew Jeffery memcpy(&console->pollfds[n + 1], &console->pollfds[n], 535f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 536329a35f5SJeremy Kerr 537329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 5385c359cc6SAndrew Jeffery console->pollfds[n].events = (short)(events & 0x7fff); 539329a35f5SJeremy Kerr 540329a35f5SJeremy Kerr return poller; 541329a35f5SJeremy Kerr } 542329a35f5SJeremy Kerr 543a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller) 544329a35f5SJeremy Kerr { 545329a35f5SJeremy Kerr int i; 546329a35f5SJeremy Kerr 547329a35f5SJeremy Kerr /* find the entry in our pollers array */ 5482834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 5492834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 550329a35f5SJeremy Kerr break; 5512834c5b1SAndrew Jeffery } 5522834c5b1SAndrew Jeffery } 553329a35f5SJeremy Kerr 554329a35f5SJeremy Kerr assert(i < console->n_pollers); 555329a35f5SJeremy Kerr 556329a35f5SJeremy Kerr console->n_pollers--; 557329a35f5SJeremy Kerr 55891b52175SAndrew Jeffery /* 55991b52175SAndrew Jeffery * Remove the item from the pollers array... 56091b52175SAndrew Jeffery * 56191b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 56291b52175SAndrew Jeffery * pointer type. 56391b52175SAndrew Jeffery */ 56491b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 565329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i + 1], 566a72711afSAndrew Jeffery sizeof(*console->pollers) * (console->n_pollers - i)); 567329a35f5SJeremy Kerr 56891b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 56991b52175SAndrew Jeffery sizeof(*console->pollers)); 57091b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 571329a35f5SJeremy Kerr 572329a35f5SJeremy Kerr /* ... and the pollfds array */ 573329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i + 1], 574329a35f5SJeremy Kerr sizeof(*console->pollfds) * 575f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 576329a35f5SJeremy Kerr 577*4e44c790SAndrew Jeffery console->pollfds = reallocarray( 578*4e44c790SAndrew Jeffery console->pollfds, (MAX_INTERNAL_POLLFD + console->n_pollers), 57991b52175SAndrew Jeffery sizeof(*console->pollfds)); 580329a35f5SJeremy Kerr 581329a35f5SJeremy Kerr free(poller); 582329a35f5SJeremy Kerr } 583329a35f5SJeremy Kerr 5846b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 5856b1fed27SJeremy Kerr int events) 5866b1fed27SJeremy Kerr { 5876b1fed27SJeremy Kerr int i; 5886b1fed27SJeremy Kerr 5896b1fed27SJeremy Kerr /* find the entry in our pollers array */ 5902834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 5912834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 5926b1fed27SJeremy Kerr break; 5932834c5b1SAndrew Jeffery } 5942834c5b1SAndrew Jeffery } 5956b1fed27SJeremy Kerr 5965c359cc6SAndrew Jeffery console->pollfds[i].events = (short)(events & 0x7fff); 5976b1fed27SJeremy Kerr } 5986b1fed27SJeremy Kerr 599fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 600fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 6011cecc5deSJohnathan Mantey { 6021cecc5deSJohnathan Mantey struct timeval now; 6031cecc5deSJohnathan Mantey int rc; 6041cecc5deSJohnathan Mantey 6051cecc5deSJohnathan Mantey rc = get_current_time(&now); 6062834c5b1SAndrew Jeffery if (rc) { 6071cecc5deSJohnathan Mantey return; 6082834c5b1SAndrew Jeffery } 6091cecc5deSJohnathan Mantey 6101cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 6111cecc5deSJohnathan Mantey } 6121cecc5deSJohnathan Mantey 6135c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time) 6141cecc5deSJohnathan Mantey { 615b70f8713SAndrew Jeffery struct timeval *earliest; 616b70f8713SAndrew Jeffery struct timeval interval; 6171cecc5deSJohnathan Mantey struct poller *poller; 6181cecc5deSJohnathan Mantey int i; 6191cecc5deSJohnathan Mantey 6201cecc5deSJohnathan Mantey earliest = NULL; 6211cecc5deSJohnathan Mantey 6221cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 6231cecc5deSJohnathan Mantey poller = console->pollers[i]; 6241cecc5deSJohnathan Mantey 6251cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6261cecc5deSJohnathan Mantey (!earliest || 6271cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))) { 6281cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6291cecc5deSJohnathan Mantey // function to timeout. 6301cecc5deSJohnathan Mantey earliest = &poller->timeout; 6311cecc5deSJohnathan Mantey } 6321cecc5deSJohnathan Mantey } 6331cecc5deSJohnathan Mantey 6341cecc5deSJohnathan Mantey if (earliest) { 6351cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6361cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6371cecc5deSJohnathan Mantey * not elapsed */ 6381cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6391cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6401cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 6410b7b0477SAndrew Jeffery } /* return from poll immediately */ 6421cecc5deSJohnathan Mantey return 0; 6430b7b0477SAndrew Jeffery 6440b7b0477SAndrew Jeffery } /* poll indefinitely */ 6451cecc5deSJohnathan Mantey return -1; 6461cecc5deSJohnathan Mantey } 6471cecc5deSJohnathan Mantey 6481cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 649329a35f5SJeremy Kerr { 650329a35f5SJeremy Kerr struct poller *poller; 651329a35f5SJeremy Kerr struct pollfd *pollfd; 652329a35f5SJeremy Kerr enum poller_ret prc; 653b70f8713SAndrew Jeffery int i; 654b70f8713SAndrew Jeffery int rc; 655d831f960SJeremy Kerr 6561a0e03b4SJeremy Kerr rc = 0; 6571a0e03b4SJeremy Kerr 658329a35f5SJeremy Kerr /* 659329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 660329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 661329a35f5SJeremy Kerr */ 662329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 663329a35f5SJeremy Kerr poller = console->pollers[i]; 664329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 6651cecc5deSJohnathan Mantey prc = POLLER_OK; 6661a0e03b4SJeremy Kerr 6671cecc5deSJohnathan Mantey /* process pending events... */ 6681cecc5deSJohnathan Mantey if (pollfd->revents) { 6691cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 670329a35f5SJeremy Kerr poller->data); 6712834c5b1SAndrew Jeffery if (prc == POLLER_EXIT) { 672329a35f5SJeremy Kerr rc = -1; 6732834c5b1SAndrew Jeffery } else if (prc == POLLER_REMOVE) { 674329a35f5SJeremy Kerr poller->remove = true; 675329a35f5SJeremy Kerr } 6762834c5b1SAndrew Jeffery } 677329a35f5SJeremy Kerr 6781cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 6791cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 6801cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 6811cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 6821cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 6831cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 6841cecc5deSJohnathan Mantey transmission. */ 6851cecc5deSJohnathan Mantey timerclear(&poller->timeout); 6861cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 6871cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 6881cecc5deSJohnathan Mantey rc = -1; 6891cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 6901cecc5deSJohnathan Mantey poller->remove = true; 6911cecc5deSJohnathan Mantey } 6921cecc5deSJohnathan Mantey } 6931cecc5deSJohnathan Mantey } 6941cecc5deSJohnathan Mantey 695329a35f5SJeremy Kerr /** 696329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 697329a35f5SJeremy Kerr * the array will have changed 698329a35f5SJeremy Kerr */ 699329a35f5SJeremy Kerr for (;;) { 700329a35f5SJeremy Kerr bool removed = false; 701329a35f5SJeremy Kerr 702329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 703329a35f5SJeremy Kerr poller = console->pollers[i]; 704329a35f5SJeremy Kerr if (poller->remove) { 70555c9712dSJeremy Kerr console_poller_unregister(console, poller); 706329a35f5SJeremy Kerr removed = true; 707329a35f5SJeremy Kerr break; 708329a35f5SJeremy Kerr } 709329a35f5SJeremy Kerr } 7102834c5b1SAndrew Jeffery if (!removed) { 711329a35f5SJeremy Kerr break; 7121a0e03b4SJeremy Kerr } 7132834c5b1SAndrew Jeffery } 7141a0e03b4SJeremy Kerr 7151a0e03b4SJeremy Kerr return rc; 7161a0e03b4SJeremy Kerr } 7171a0e03b4SJeremy Kerr 718769cee1aSJeremy Kerr static void sighandler(int signal) 719769cee1aSJeremy Kerr { 7202834c5b1SAndrew Jeffery if (signal == SIGINT) { 721769cee1aSJeremy Kerr sigint = true; 722769cee1aSJeremy Kerr } 7232834c5b1SAndrew Jeffery } 724769cee1aSJeremy Kerr 7251a0e03b4SJeremy Kerr int run_console(struct console *console) 7261a0e03b4SJeremy Kerr { 7275c359cc6SAndrew Jeffery sighandler_t sighandler_save = signal(SIGINT, sighandler); 7281cecc5deSJohnathan Mantey struct timeval tv; 7295c359cc6SAndrew Jeffery long timeout; 7305c359cc6SAndrew Jeffery ssize_t rc; 731769cee1aSJeremy Kerr 732769cee1aSJeremy Kerr rc = 0; 733769cee1aSJeremy Kerr 734d831f960SJeremy Kerr for (;;) { 735d831f960SJeremy Kerr uint8_t buf[4096]; 736d831f960SJeremy Kerr 7371764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7381764145dSJeremy Kerr 739769cee1aSJeremy Kerr if (sigint) { 740769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 741769cee1aSJeremy Kerr break; 742769cee1aSJeremy Kerr } 743769cee1aSJeremy Kerr 7441cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7451cecc5deSJohnathan Mantey if (rc) { 7461cecc5deSJohnathan Mantey warn("Failed to read current time"); 7471cecc5deSJohnathan Mantey break; 7481cecc5deSJohnathan Mantey } 7491cecc5deSJohnathan Mantey 7501cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7511cecc5deSJohnathan Mantey 752329a35f5SJeremy Kerr rc = poll(console->pollfds, 7535c359cc6SAndrew Jeffery console->n_pollers + MAX_INTERNAL_POLLFD, 7545c359cc6SAndrew Jeffery (int)timeout); 7551cecc5deSJohnathan Mantey 756d831f960SJeremy Kerr if (rc < 0) { 757769cee1aSJeremy Kerr if (errno == EINTR) { 758769cee1aSJeremy Kerr continue; 7590b7b0477SAndrew Jeffery } 760d831f960SJeremy Kerr warn("poll error"); 761769cee1aSJeremy Kerr break; 762769cee1aSJeremy Kerr } 763d831f960SJeremy Kerr 764329a35f5SJeremy Kerr /* process internal fd first */ 765329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 76630ea6385SAndrew Jeffery rc = read(console->tty.fd, buf, sizeof(buf)); 767d831f960SJeremy Kerr if (rc <= 0) { 768d831f960SJeremy Kerr warn("Error reading from tty device"); 769769cee1aSJeremy Kerr rc = -1; 770769cee1aSJeremy Kerr break; 771d831f960SJeremy Kerr } 772f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 7732834c5b1SAndrew Jeffery if (rc) { 774769cee1aSJeremy Kerr break; 775d831f960SJeremy Kerr } 7762834c5b1SAndrew Jeffery } 777d831f960SJeremy Kerr 778f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 779f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 780f9c8f6caSCheng C Yang } 781f9c8f6caSCheng C Yang 782329a35f5SJeremy Kerr /* ... and then the pollers */ 7831cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 7842834c5b1SAndrew Jeffery if (rc) { 785769cee1aSJeremy Kerr break; 7861a0e03b4SJeremy Kerr } 7872834c5b1SAndrew Jeffery } 788769cee1aSJeremy Kerr 789769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 790f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 791769cee1aSJeremy Kerr 792769cee1aSJeremy Kerr return rc ? -1 : 0; 7931a0e03b4SJeremy Kerr } 794d831f960SJeremy Kerr static const struct option options[] = { 795d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 796954be0fbSAndrew Jeffery { "console-id", required_argument, 0, 'i' }, 797f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 798d831f960SJeremy Kerr }; 799d831f960SJeremy Kerr 800d831f960SJeremy Kerr int main(int argc, char **argv) 801d831f960SJeremy Kerr { 802d66195c1SJeremy Kerr const char *config_filename = NULL; 8036221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 804954be0fbSAndrew Jeffery const char *console_id = NULL; 8051a0e03b4SJeremy Kerr struct console *console; 806d66195c1SJeremy Kerr struct config *config; 807d66195c1SJeremy Kerr int rc; 808d831f960SJeremy Kerr 809d831f960SJeremy Kerr for (;;) { 810b70f8713SAndrew Jeffery int c; 811b70f8713SAndrew Jeffery int idx; 812d831f960SJeremy Kerr 813954be0fbSAndrew Jeffery c = getopt_long(argc, argv, "c:i:", options, &idx); 8142834c5b1SAndrew Jeffery if (c == -1) { 815d831f960SJeremy Kerr break; 8162834c5b1SAndrew Jeffery } 817d831f960SJeremy Kerr 818d831f960SJeremy Kerr switch (c) { 819d66195c1SJeremy Kerr case 'c': 820d66195c1SJeremy Kerr config_filename = optarg; 821d831f960SJeremy Kerr break; 822954be0fbSAndrew Jeffery case 'i': 823954be0fbSAndrew Jeffery console_id = optarg; 824954be0fbSAndrew Jeffery break; 825d831f960SJeremy Kerr case 'h': 826d831f960SJeremy Kerr case '?': 827d831f960SJeremy Kerr usage(argv[0]); 828d66195c1SJeremy Kerr return EXIT_SUCCESS; 829d831f960SJeremy Kerr } 830d831f960SJeremy Kerr } 831d831f960SJeremy Kerr 8322834c5b1SAndrew Jeffery if (optind < argc) { 8336221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8342834c5b1SAndrew Jeffery } 8356221ce94SVishwanatha Subbanna 836d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 837d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 838a72711afSAndrew Jeffery console->pollfds = 839a72711afSAndrew Jeffery calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds)); 840f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 841329a35f5SJeremy Kerr 842d66195c1SJeremy Kerr config = config_init(config_filename); 843d831f960SJeremy Kerr 844954be0fbSAndrew Jeffery if (set_socket_info(console, config, console_id)) { 84529c59c44SAndrew Jeffery rc = -1; 84629c59c44SAndrew Jeffery goto out_config_fini; 847b14ca19cSNinad Palsule } 848b14ca19cSNinad Palsule 849d769eecfSAndrew Jeffery rc = tty_init(console, config, config_tty_kname); 8502834c5b1SAndrew Jeffery if (rc) { 851d66195c1SJeremy Kerr goto out_config_fini; 8522834c5b1SAndrew Jeffery } 853d831f960SJeremy Kerr 854f9c8f6caSCheng C Yang dbus_init(console, config); 855f9c8f6caSCheng C Yang 856d47963e5SJeremy Kerr handlers_init(console, config); 857d831f960SJeremy Kerr 8581a0e03b4SJeremy Kerr rc = run_console(console); 859d831f960SJeremy Kerr 8601a0e03b4SJeremy Kerr handlers_fini(console); 861d831f960SJeremy Kerr 86230ea6385SAndrew Jeffery tty_fini(console); 86330ea6385SAndrew Jeffery 864d66195c1SJeremy Kerr out_config_fini: 865d66195c1SJeremy Kerr config_fini(config); 866d66195c1SJeremy Kerr 86789ea8198SJeremy Kerr free(console->pollers); 86889ea8198SJeremy Kerr free(console->pollfds); 8691a0e03b4SJeremy Kerr free(console); 870d831f960SJeremy Kerr 871d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 872d831f960SJeremy Kerr } 873