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> 3787e344cdSJoel Stanley #include <poll.h> 38d831f960SJeremy Kerr 391a0e03b4SJeremy Kerr #include "console-server.h" 40d831f960SJeremy Kerr 41f9c8f6caSCheng C Yang #define DBUS_ERR "org.openbmc.error" 42f9c8f6caSCheng C Yang #define DBUS_NAME "xyz.openbmc_project.console" 43f9c8f6caSCheng C Yang #define OBJ_NAME "/xyz/openbmc_project/console" 44f9c8f6caSCheng C Yang 451a0e03b4SJeremy Kerr struct console { 4617217845SJeremy Kerr const char *tty_kname; 4717217845SJeremy Kerr char *tty_sysfs_devnode; 4817217845SJeremy Kerr char *tty_dev; 49957818b4SJeremy Kerr int tty_sirq; 50fd883a88SAndrew Jeffery uint16_t tty_lpc_addr; 51c7fbcd48SBenjamin Fair speed_t tty_baud; 52d831f960SJeremy Kerr int tty_fd; 53329a35f5SJeremy Kerr 54f733c85aSJeremy Kerr struct ringbuffer *rb; 55f733c85aSJeremy Kerr 561a0e03b4SJeremy Kerr struct handler **handlers; 575c359cc6SAndrew Jeffery long n_handlers; 58329a35f5SJeremy Kerr 59329a35f5SJeremy Kerr struct poller **pollers; 605c359cc6SAndrew Jeffery long n_pollers; 61329a35f5SJeremy Kerr 62329a35f5SJeremy Kerr struct pollfd *pollfds; 63f9c8f6caSCheng C Yang struct sd_bus *bus; 64d831f960SJeremy Kerr }; 65d831f960SJeremy Kerr 66329a35f5SJeremy Kerr struct poller { 67329a35f5SJeremy Kerr struct handler *handler; 68329a35f5SJeremy Kerr void *data; 691cecc5deSJohnathan Mantey poller_event_fn_t event_fn; 701cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn; 711cecc5deSJohnathan Mantey struct timeval timeout; 72329a35f5SJeremy Kerr bool remove; 73329a35f5SJeremy Kerr }; 74329a35f5SJeremy Kerr 75f9c8f6caSCheng C Yang /* we have two extra entry in the pollfds array for the VUART tty */ 76f9c8f6caSCheng C Yang enum internal_pollfds { 77f9c8f6caSCheng C Yang POLLFD_HOSTTTY = 0, 78f9c8f6caSCheng C Yang POLLFD_DBUS = 1, 79f9c8f6caSCheng C Yang MAX_INTERNAL_POLLFD = 2, 80f9c8f6caSCheng C Yang }; 81329a35f5SJeremy Kerr 82f733c85aSJeremy Kerr /* size of the shared backlog ringbuffer */ 835db8c792SAndrew Jeffery const size_t buffer_size = 128ul * 1024ul; 84f733c85aSJeremy Kerr 85769cee1aSJeremy Kerr /* state shared with the signal handler */ 86769cee1aSJeremy Kerr static bool sigint; 87329a35f5SJeremy Kerr 88d831f960SJeremy Kerr static void usage(const char *progname) 89d831f960SJeremy Kerr { 90d831f960SJeremy Kerr fprintf(stderr, 916221ce94SVishwanatha Subbanna "usage: %s [options] <DEVICE>\n" 92d831f960SJeremy Kerr "\n" 93d831f960SJeremy Kerr "Options:\n" 94d66195c1SJeremy Kerr " --config <FILE> Use FILE for configuration\n" 95d831f960SJeremy Kerr "", 96d831f960SJeremy Kerr progname); 97d831f960SJeremy Kerr } 98d831f960SJeremy Kerr 9917217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 1001a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 10117217845SJeremy Kerr { 10217217845SJeremy Kerr char *tty_class_device_link; 10317217845SJeremy Kerr char *tty_device_tty_dir; 10417217845SJeremy Kerr char *tty_device_reldir; 10545ad7676SYi Li char *tty_path_input; 10645ad7676SYi Li char *tty_path_input_real; 10745ad7676SYi Li char *tty_kname_real; 10817217845SJeremy Kerr int rc; 10917217845SJeremy Kerr 11017217845SJeremy Kerr tty_class_device_link = NULL; 11117217845SJeremy Kerr tty_device_tty_dir = NULL; 11217217845SJeremy Kerr tty_device_reldir = NULL; 11345ad7676SYi Li tty_path_input = NULL; 11445ad7676SYi Li tty_path_input_real = NULL; 11545ad7676SYi Li tty_kname_real = NULL; 11617217845SJeremy Kerr 11745ad7676SYi Li /* udev may rename the tty name with a symbol link, try to resolve */ 11845ad7676SYi Li rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname); 1192834c5b1SAndrew Jeffery if (rc < 0) { 12017217845SJeremy Kerr return -1; 1212834c5b1SAndrew Jeffery } 12217217845SJeremy Kerr 12345ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 12445ad7676SYi Li if (!tty_path_input_real) { 12545ad7676SYi Li warn("Can't find realpath for /dev/%s", console->tty_kname); 12615792aa7SAndrew Jeffery rc = -1; 12745ad7676SYi Li goto out_free; 12845ad7676SYi Li } 12945ad7676SYi Li 13045ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 13145ad7676SYi Li if (!tty_kname_real) { 13245ad7676SYi Li warn("Can't find real name for /dev/%s", console->tty_kname); 13315792aa7SAndrew Jeffery rc = -1; 13445ad7676SYi Li goto out_free; 13545ad7676SYi Li } 13645ad7676SYi Li 137a72711afSAndrew Jeffery rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s", 138a72711afSAndrew Jeffery tty_kname_real); 1392834c5b1SAndrew Jeffery if (rc < 0) { 14045ad7676SYi Li goto out_free; 1412834c5b1SAndrew Jeffery } 14245ad7676SYi Li 14317217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 14445ad7676SYi Li if (!tty_device_tty_dir) { 14545ad7676SYi Li warn("Can't query sysfs for device %s", tty_kname_real); 14615792aa7SAndrew Jeffery rc = -1; 14717217845SJeremy Kerr goto out_free; 14817217845SJeremy Kerr } 14917217845SJeremy Kerr 15017217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 1512834c5b1SAndrew Jeffery if (rc < 0) { 15217217845SJeremy Kerr goto out_free; 1532834c5b1SAndrew Jeffery } 15417217845SJeremy Kerr 1551a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1562834c5b1SAndrew Jeffery if (!console->tty_sysfs_devnode) { 15745ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 1582834c5b1SAndrew Jeffery } 15917217845SJeremy Kerr 16045ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 1612834c5b1SAndrew Jeffery if (rc < 0) { 16217217845SJeremy Kerr goto out_free; 1632834c5b1SAndrew Jeffery } 16417217845SJeremy Kerr 16517217845SJeremy Kerr rc = 0; 16617217845SJeremy Kerr 16717217845SJeremy Kerr out_free: 16817217845SJeremy Kerr free(tty_class_device_link); 16917217845SJeremy Kerr free(tty_device_tty_dir); 17017217845SJeremy Kerr free(tty_device_reldir); 17145ad7676SYi Li free(tty_path_input); 17245ad7676SYi Li free(tty_path_input_real); 17317217845SJeremy Kerr return rc; 17417217845SJeremy Kerr } 17517217845SJeremy Kerr 1761a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 177957818b4SJeremy Kerr int value) 178957818b4SJeremy Kerr { 179957818b4SJeremy Kerr char *path; 180957818b4SJeremy Kerr FILE *fp; 181957818b4SJeremy Kerr int rc; 182957818b4SJeremy Kerr 1831a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 1842834c5b1SAndrew Jeffery if (rc < 0) { 185957818b4SJeremy Kerr return -1; 1862834c5b1SAndrew Jeffery } 187957818b4SJeremy Kerr 188957818b4SJeremy Kerr fp = fopen(path, "w"); 189957818b4SJeremy Kerr if (!fp) { 190a72711afSAndrew Jeffery warn("Can't access attribute %s on device %s", name, 191a72711afSAndrew Jeffery console->tty_kname); 192957818b4SJeremy Kerr rc = -1; 193957818b4SJeremy Kerr goto out_free; 194957818b4SJeremy Kerr } 195957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 196957818b4SJeremy Kerr 197957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 1982834c5b1SAndrew Jeffery if (rc < 0) { 199a72711afSAndrew Jeffery warn("Error writing to %s attribute of device %s", name, 200a72711afSAndrew Jeffery console->tty_kname); 2012834c5b1SAndrew Jeffery } 202957818b4SJeremy Kerr fclose(fp); 203957818b4SJeremy Kerr 204957818b4SJeremy Kerr out_free: 205957818b4SJeremy Kerr free(path); 206957818b4SJeremy Kerr return rc; 207957818b4SJeremy Kerr } 208957818b4SJeremy Kerr 209d831f960SJeremy Kerr /** 210c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 21154e9569dSJeremy Kerr */ 21254e9569dSJeremy Kerr static void tty_init_termios(struct console *console) 21354e9569dSJeremy Kerr { 21454e9569dSJeremy Kerr struct termios termios; 21554e9569dSJeremy Kerr int rc; 21654e9569dSJeremy Kerr 21754e9569dSJeremy Kerr rc = tcgetattr(console->tty_fd, &termios); 21854e9569dSJeremy Kerr if (rc) { 21954e9569dSJeremy Kerr warn("Can't read tty termios"); 22054e9569dSJeremy Kerr return; 22154e9569dSJeremy Kerr } 22254e9569dSJeremy Kerr 223c7fbcd48SBenjamin Fair if (console->tty_baud) { 2242834c5b1SAndrew Jeffery if (cfsetspeed(&termios, console->tty_baud) < 0) { 225c7fbcd48SBenjamin Fair warn("Couldn't set speeds for %s", console->tty_kname); 226c7fbcd48SBenjamin Fair } 2272834c5b1SAndrew Jeffery } 228c7fbcd48SBenjamin Fair 229c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 230c7fbcd48SBenjamin Fair * the underlying terminal input/output. 231c7fbcd48SBenjamin Fair */ 23254e9569dSJeremy Kerr cfmakeraw(&termios); 233c7fbcd48SBenjamin Fair 23454e9569dSJeremy Kerr rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 2352834c5b1SAndrew Jeffery if (rc) { 236c7fbcd48SBenjamin Fair warn("Can't set terminal options for %s", console->tty_kname); 23754e9569dSJeremy Kerr } 2382834c5b1SAndrew Jeffery } 23954e9569dSJeremy Kerr 240f9c8f6caSCheng C Yang static void tty_change_baudrate(struct console *console) 241f9c8f6caSCheng C Yang { 242f9c8f6caSCheng C Yang struct handler *handler; 243f9c8f6caSCheng C Yang int i, rc; 244f9c8f6caSCheng C Yang 245f9c8f6caSCheng C Yang tty_init_termios(console); 246f9c8f6caSCheng C Yang 247f9c8f6caSCheng C Yang for (i = 0; i < console->n_handlers; i++) { 248f9c8f6caSCheng C Yang handler = console->handlers[i]; 2492834c5b1SAndrew Jeffery if (!handler->baudrate) { 250f9c8f6caSCheng C Yang continue; 2512834c5b1SAndrew Jeffery } 252f9c8f6caSCheng C Yang 253f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 2542834c5b1SAndrew Jeffery if (rc) { 255f9c8f6caSCheng C Yang warnx("Can't set terminal baudrate for handler %s", 256f9c8f6caSCheng C Yang handler->name); 257f9c8f6caSCheng C Yang } 258f9c8f6caSCheng C Yang } 2592834c5b1SAndrew Jeffery } 260f9c8f6caSCheng C Yang 26154e9569dSJeremy Kerr /** 262d831f960SJeremy Kerr * Open and initialise the serial device 263d831f960SJeremy Kerr */ 2641a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 265d831f960SJeremy Kerr { 2662834c5b1SAndrew Jeffery if (console->tty_sirq) { 2671a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2682834c5b1SAndrew Jeffery } 2692834c5b1SAndrew Jeffery if (console->tty_lpc_addr) { 2701a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2711a0e03b4SJeremy Kerr console->tty_lpc_addr); 2722834c5b1SAndrew Jeffery } 273957818b4SJeremy Kerr 2741a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2751a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2761a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 277d831f960SJeremy Kerr return -1; 278d831f960SJeremy Kerr } 279d831f960SJeremy Kerr 280d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 281d831f960SJeremy Kerr * we detect larger amounts of data 282d831f960SJeremy Kerr */ 2831a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 284d831f960SJeremy Kerr 28554e9569dSJeremy Kerr tty_init_termios(console); 28654e9569dSJeremy Kerr 287329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 288329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 289329a35f5SJeremy Kerr 290d831f960SJeremy Kerr return 0; 291d831f960SJeremy Kerr } 292d831f960SJeremy Kerr 293d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 294d66195c1SJeremy Kerr { 295fd883a88SAndrew Jeffery unsigned long parsed; 296d66195c1SJeremy Kerr const char *val; 297d66195c1SJeremy Kerr char *endp; 298d66195c1SJeremy Kerr int rc; 299d66195c1SJeremy Kerr 300d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 301d66195c1SJeremy Kerr if (val) { 302fd883a88SAndrew Jeffery errno = 0; 303fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 304fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 305fd883a88SAndrew Jeffery warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'", 306fd883a88SAndrew Jeffery val); 307fd883a88SAndrew Jeffery return -1; 308fd883a88SAndrew Jeffery } 309fd883a88SAndrew Jeffery 310fd883a88SAndrew Jeffery if (parsed > UINT16_MAX) { 311fd883a88SAndrew Jeffery warn("Invalid LPC address '%s'", val); 312fd883a88SAndrew Jeffery return -1; 313fd883a88SAndrew Jeffery } 314fd883a88SAndrew Jeffery 315fd883a88SAndrew Jeffery console->tty_lpc_addr = (uint16_t)parsed; 316d66195c1SJeremy Kerr if (endp == optarg) { 317d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 318d66195c1SJeremy Kerr return -1; 319d66195c1SJeremy Kerr } 320d66195c1SJeremy Kerr } 321d66195c1SJeremy Kerr 322d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 323d66195c1SJeremy Kerr if (val) { 324fd883a88SAndrew Jeffery errno = 0; 325fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 326fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 327fd883a88SAndrew Jeffery warn("Cannot interpret 'sirq' value as an unsigned long: '%s'", 328fd883a88SAndrew Jeffery val); 329fd883a88SAndrew Jeffery } 330fd883a88SAndrew Jeffery 3312834c5b1SAndrew Jeffery if (parsed > 16) { 332fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 3332834c5b1SAndrew Jeffery } 334fd883a88SAndrew Jeffery 335fd883a88SAndrew Jeffery console->tty_sirq = (int)parsed; 3362834c5b1SAndrew Jeffery if (endp == optarg) { 337d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 338d66195c1SJeremy Kerr } 3392834c5b1SAndrew Jeffery } 340d66195c1SJeremy Kerr 341c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 342c7fbcd48SBenjamin Fair if (val) { 3432834c5b1SAndrew Jeffery if (config_parse_baud(&console->tty_baud, val)) { 344c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 345c7fbcd48SBenjamin Fair } 3462834c5b1SAndrew Jeffery } 347c7fbcd48SBenjamin Fair 348d66195c1SJeremy Kerr if (!console->tty_kname) { 349d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 350d66195c1SJeremy Kerr return -1; 351d66195c1SJeremy Kerr } 352d66195c1SJeremy Kerr 353d66195c1SJeremy Kerr rc = tty_find_device(console); 3542834c5b1SAndrew Jeffery if (rc) { 355d66195c1SJeremy Kerr return rc; 3562834c5b1SAndrew Jeffery } 357d66195c1SJeremy Kerr 358d66195c1SJeremy Kerr rc = tty_init_io(console); 359d66195c1SJeremy Kerr return rc; 360d66195c1SJeremy Kerr } 361d66195c1SJeremy Kerr 3621a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 363d831f960SJeremy Kerr { 3641a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 365d831f960SJeremy Kerr } 366d831f960SJeremy Kerr 367f9c8f6caSCheng C Yang static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 368f9c8f6caSCheng C Yang sd_bus_error *err) 369f9c8f6caSCheng C Yang { 370f9c8f6caSCheng C Yang struct console *console = userdata; 371f9c8f6caSCheng C Yang uint32_t baudrate; 372f9c8f6caSCheng C Yang speed_t speed; 373f9c8f6caSCheng C Yang int r; 374f9c8f6caSCheng C Yang 375f9c8f6caSCheng C Yang if (!console) { 376f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 377f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", 0); 378f9c8f6caSCheng C Yang } 379f9c8f6caSCheng C Yang 380f9c8f6caSCheng C Yang r = sd_bus_message_read(msg, "u", &baudrate); 381f9c8f6caSCheng C Yang if (r < 0) { 382f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 383f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 384f9c8f6caSCheng C Yang } 385f9c8f6caSCheng C Yang 386f9c8f6caSCheng C Yang speed = parse_int_to_baud(baudrate); 387f9c8f6caSCheng C Yang if (!speed) { 388f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%u'", baudrate); 389f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 390f9c8f6caSCheng C Yang } 391f9c8f6caSCheng C Yang 392f9c8f6caSCheng C Yang console->tty_baud = speed; 393f9c8f6caSCheng C Yang tty_change_baudrate(console); 394f9c8f6caSCheng C Yang 395f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", r); 396f9c8f6caSCheng C Yang } 397f9c8f6caSCheng C Yang 398fd048328SAndrew Jeffery static int get_handler(sd_bus *bus __attribute__((unused)), 399fd048328SAndrew Jeffery const char *path __attribute__((unused)), 400fd048328SAndrew Jeffery const char *interface __attribute__((unused)), 401fd048328SAndrew Jeffery const char *property __attribute__((unused)), 402fd048328SAndrew Jeffery sd_bus_message *reply, void *userdata, 403a72711afSAndrew Jeffery sd_bus_error *error __attribute__((unused))) 404a72711afSAndrew Jeffery { 405f9c8f6caSCheng C Yang struct console *console = userdata; 406f9c8f6caSCheng C Yang uint32_t baudrate; 407f9c8f6caSCheng C Yang int r; 408f9c8f6caSCheng C Yang 409f9c8f6caSCheng C Yang baudrate = parse_baud_to_int(console->tty_baud); 4102834c5b1SAndrew Jeffery if (!baudrate) { 411f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 4122834c5b1SAndrew Jeffery } 413f9c8f6caSCheng C Yang 414f9c8f6caSCheng C Yang r = sd_bus_message_append(reply, "u", baudrate); 415f9c8f6caSCheng C Yang 416f9c8f6caSCheng C Yang return r; 417f9c8f6caSCheng C Yang } 418f9c8f6caSCheng C Yang 419f9c8f6caSCheng C Yang static const sd_bus_vtable console_vtable[] = { 420f9c8f6caSCheng C Yang SD_BUS_VTABLE_START(0), 421f9c8f6caSCheng C Yang SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 422f9c8f6caSCheng C Yang SD_BUS_VTABLE_UNPRIVILEGED), 423f9c8f6caSCheng C Yang SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 424a72711afSAndrew Jeffery SD_BUS_VTABLE_END, 425a72711afSAndrew Jeffery }; 426f9c8f6caSCheng C Yang 427a72711afSAndrew Jeffery static void dbus_init(struct console *console, 428a72711afSAndrew Jeffery struct config *config __attribute__((unused))) 429f9c8f6caSCheng C Yang { 430f9c8f6caSCheng C Yang int dbus_poller = 0; 431f9c8f6caSCheng C Yang int fd, r; 432f9c8f6caSCheng C Yang 433f9c8f6caSCheng C Yang if (!console) { 434f9c8f6caSCheng C Yang warnx("Couldn't get valid console"); 435f9c8f6caSCheng C Yang return; 436f9c8f6caSCheng C Yang } 437f9c8f6caSCheng C Yang 438f9c8f6caSCheng C Yang r = sd_bus_default_system(&console->bus); 439f9c8f6caSCheng C Yang if (r < 0) { 440f9c8f6caSCheng C Yang warnx("Failed to connect to system bus: %s", strerror(-r)); 441f9c8f6caSCheng C Yang return; 442f9c8f6caSCheng C Yang } 443f9c8f6caSCheng C Yang 444f9c8f6caSCheng C Yang r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 445f9c8f6caSCheng C Yang console_vtable, console); 446f9c8f6caSCheng C Yang if (r < 0) { 447f9c8f6caSCheng C Yang warnx("Failed to issue method call: %s", strerror(-r)); 448f9c8f6caSCheng C Yang return; 449f9c8f6caSCheng C Yang } 450f9c8f6caSCheng C Yang 451a72711afSAndrew Jeffery r = sd_bus_request_name(console->bus, DBUS_NAME, 452a72711afSAndrew Jeffery SD_BUS_NAME_ALLOW_REPLACEMENT | 453a72711afSAndrew Jeffery SD_BUS_NAME_REPLACE_EXISTING); 454f9c8f6caSCheng C Yang if (r < 0) { 455f9c8f6caSCheng C Yang warnx("Failed to acquire service name: %s", strerror(-r)); 456f9c8f6caSCheng C Yang return; 457f9c8f6caSCheng C Yang } 458f9c8f6caSCheng C Yang 459f9c8f6caSCheng C Yang fd = sd_bus_get_fd(console->bus); 460f9c8f6caSCheng C Yang if (fd < 0) { 461f9c8f6caSCheng C Yang warnx("Couldn't get the bus file descriptor"); 462f9c8f6caSCheng C Yang return; 463f9c8f6caSCheng C Yang } 464f9c8f6caSCheng C Yang 465f9c8f6caSCheng C Yang dbus_poller = POLLFD_DBUS; 466f9c8f6caSCheng C Yang 467f9c8f6caSCheng C Yang console->pollfds[dbus_poller].fd = fd; 468f9c8f6caSCheng C Yang console->pollfds[dbus_poller].events = POLLIN; 469f9c8f6caSCheng C Yang } 470f9c8f6caSCheng C Yang 471d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 472d831f960SJeremy Kerr { 473750fb0c0SAndrew Jeffery /* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 4741a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 4751a0e03b4SJeremy Kerr struct handler *handler; 476021b91f0SJeremy Kerr int i, rc; 477d831f960SJeremy Kerr 4781a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4791a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 480d831f960SJeremy Kerr 4815c359cc6SAndrew Jeffery printf("%ld handler%s\n", console->n_handlers, 4821a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 483d831f960SJeremy Kerr 4841a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4851a0e03b4SJeremy Kerr handler = console->handlers[i]; 4861a0e03b4SJeremy Kerr 487021b91f0SJeremy Kerr rc = 0; 4882834c5b1SAndrew Jeffery if (handler->init) { 489021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 4902834c5b1SAndrew Jeffery } 491021b91f0SJeremy Kerr 492021b91f0SJeremy Kerr handler->active = rc == 0; 493021b91f0SJeremy Kerr 494021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 495021b91f0SJeremy Kerr handler->active ? "" : "in"); 496d831f960SJeremy Kerr } 497d831f960SJeremy Kerr } 498d831f960SJeremy Kerr 4991a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 500d831f960SJeremy Kerr { 5011a0e03b4SJeremy Kerr struct handler *handler; 5021a0e03b4SJeremy Kerr int i; 5031a0e03b4SJeremy Kerr 5041a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 5051a0e03b4SJeremy Kerr handler = console->handlers[i]; 5062834c5b1SAndrew Jeffery if (handler->fini && handler->active) { 5071a0e03b4SJeremy Kerr handler->fini(handler); 5081a0e03b4SJeremy Kerr } 509d831f960SJeremy Kerr } 5102834c5b1SAndrew Jeffery } 511d831f960SJeremy Kerr 5121cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 5131cecc5deSJohnathan Mantey { 5141cecc5deSJohnathan Mantey struct timespec t; 5151cecc5deSJohnathan Mantey int rc; 5161cecc5deSJohnathan Mantey 5171cecc5deSJohnathan Mantey /* 5181cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 5191cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 5201cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 5211cecc5deSJohnathan Mantey */ 5221cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 5232834c5b1SAndrew Jeffery if (rc) { 5241cecc5deSJohnathan Mantey return rc; 5252834c5b1SAndrew Jeffery } 5261cecc5deSJohnathan Mantey 5271cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 5281cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 5291cecc5deSJohnathan Mantey 5301cecc5deSJohnathan Mantey return 0; 5311cecc5deSJohnathan Mantey } 5321cecc5deSJohnathan Mantey 533a72711afSAndrew Jeffery struct ringbuffer_consumer * 534a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console, 535f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 536d831f960SJeremy Kerr { 537f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 538d831f960SJeremy Kerr } 539d831f960SJeremy Kerr 54055c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 541a72711afSAndrew Jeffery struct handler *handler, 542a72711afSAndrew Jeffery poller_event_fn_t poller_fn, 5431cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 5441cecc5deSJohnathan Mantey int events, void *data) 545d831f960SJeremy Kerr { 546329a35f5SJeremy Kerr struct poller *poller; 5475c359cc6SAndrew Jeffery long n; 548329a35f5SJeremy Kerr 549329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 550329a35f5SJeremy Kerr poller->remove = false; 551329a35f5SJeremy Kerr poller->handler = handler; 5521cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5531cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 554329a35f5SJeremy Kerr poller->data = data; 555329a35f5SJeremy Kerr 556329a35f5SJeremy Kerr /* add one to our pollers array */ 557329a35f5SJeremy Kerr n = console->n_pollers++; 55891b52175SAndrew Jeffery /* 55991b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 56091b52175SAndrew Jeffery * pointer type. 56191b52175SAndrew Jeffery */ 56291b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 56391b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 56491b52175SAndrew Jeffery sizeof(*console->pollers)); 56591b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 566329a35f5SJeremy Kerr 567329a35f5SJeremy Kerr console->pollers[n] = poller; 568329a35f5SJeremy Kerr 569329a35f5SJeremy Kerr /* increase pollfds array too */ 570a72711afSAndrew Jeffery console->pollfds = 57191b52175SAndrew Jeffery reallocarray(console->pollfds, 57291b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 57391b52175SAndrew Jeffery sizeof(*console->pollfds)); 574329a35f5SJeremy Kerr 575329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 576a72711afSAndrew Jeffery memcpy(&console->pollfds[n + 1], &console->pollfds[n], 577f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 578329a35f5SJeremy Kerr 579329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 5805c359cc6SAndrew Jeffery console->pollfds[n].events = (short)(events & 0x7fff); 581329a35f5SJeremy Kerr 582329a35f5SJeremy Kerr return poller; 583329a35f5SJeremy Kerr } 584329a35f5SJeremy Kerr 585a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller) 586329a35f5SJeremy Kerr { 587329a35f5SJeremy Kerr int i; 588329a35f5SJeremy Kerr 589329a35f5SJeremy 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) { 592329a35f5SJeremy Kerr break; 5932834c5b1SAndrew Jeffery } 5942834c5b1SAndrew Jeffery } 595329a35f5SJeremy Kerr 596329a35f5SJeremy Kerr assert(i < console->n_pollers); 597329a35f5SJeremy Kerr 598329a35f5SJeremy Kerr console->n_pollers--; 599329a35f5SJeremy Kerr 60091b52175SAndrew Jeffery /* 60191b52175SAndrew Jeffery * Remove the item from the pollers array... 60291b52175SAndrew Jeffery * 60391b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 60491b52175SAndrew Jeffery * pointer type. 60591b52175SAndrew Jeffery */ 60691b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 607329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i + 1], 608a72711afSAndrew Jeffery sizeof(*console->pollers) * (console->n_pollers - i)); 609329a35f5SJeremy Kerr 61091b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 61191b52175SAndrew Jeffery sizeof(*console->pollers)); 61291b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 613329a35f5SJeremy Kerr 614329a35f5SJeremy Kerr /* ... and the pollfds array */ 615329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i + 1], 616329a35f5SJeremy Kerr sizeof(*console->pollfds) * 617f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 618329a35f5SJeremy Kerr 619a72711afSAndrew Jeffery console->pollfds = 62091b52175SAndrew Jeffery reallocarray(console->pollfds, 62191b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 62291b52175SAndrew Jeffery sizeof(*console->pollfds)); 623329a35f5SJeremy Kerr 624329a35f5SJeremy Kerr free(poller); 625329a35f5SJeremy Kerr } 626329a35f5SJeremy Kerr 6276b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 6286b1fed27SJeremy Kerr int events) 6296b1fed27SJeremy Kerr { 6306b1fed27SJeremy Kerr int i; 6316b1fed27SJeremy Kerr 6326b1fed27SJeremy Kerr /* find the entry in our pollers array */ 6332834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 6342834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 6356b1fed27SJeremy Kerr break; 6362834c5b1SAndrew Jeffery } 6372834c5b1SAndrew Jeffery } 6386b1fed27SJeremy Kerr 6395c359cc6SAndrew Jeffery console->pollfds[i].events = (short)(events & 0x7fff); 6406b1fed27SJeremy Kerr } 6416b1fed27SJeremy Kerr 642fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 643fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 6441cecc5deSJohnathan Mantey { 6451cecc5deSJohnathan Mantey struct timeval now; 6461cecc5deSJohnathan Mantey int rc; 6471cecc5deSJohnathan Mantey 6481cecc5deSJohnathan Mantey rc = get_current_time(&now); 6492834c5b1SAndrew Jeffery if (rc) { 6501cecc5deSJohnathan Mantey return; 6512834c5b1SAndrew Jeffery } 6521cecc5deSJohnathan Mantey 6531cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 6541cecc5deSJohnathan Mantey } 6551cecc5deSJohnathan Mantey 6565c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time) 6571cecc5deSJohnathan Mantey { 6581cecc5deSJohnathan Mantey struct timeval *earliest, interval; 6591cecc5deSJohnathan Mantey struct poller *poller; 6601cecc5deSJohnathan Mantey int i; 6611cecc5deSJohnathan Mantey 6621cecc5deSJohnathan Mantey earliest = NULL; 6631cecc5deSJohnathan Mantey 6641cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 6651cecc5deSJohnathan Mantey poller = console->pollers[i]; 6661cecc5deSJohnathan Mantey 6671cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6681cecc5deSJohnathan Mantey (!earliest || 6691cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))) { 6701cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6711cecc5deSJohnathan Mantey // function to timeout. 6721cecc5deSJohnathan Mantey earliest = &poller->timeout; 6731cecc5deSJohnathan Mantey } 6741cecc5deSJohnathan Mantey } 6751cecc5deSJohnathan Mantey 6761cecc5deSJohnathan Mantey if (earliest) { 6771cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6781cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6791cecc5deSJohnathan Mantey * not elapsed */ 6801cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6811cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6821cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 683*0b7b0477SAndrew Jeffery } /* return from poll immediately */ 6841cecc5deSJohnathan Mantey return 0; 685*0b7b0477SAndrew Jeffery 686*0b7b0477SAndrew Jeffery } /* poll indefinitely */ 6871cecc5deSJohnathan Mantey return -1; 6881cecc5deSJohnathan Mantey } 6891cecc5deSJohnathan Mantey 6901cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 691329a35f5SJeremy Kerr { 692329a35f5SJeremy Kerr struct poller *poller; 693329a35f5SJeremy Kerr struct pollfd *pollfd; 694329a35f5SJeremy Kerr enum poller_ret prc; 695329a35f5SJeremy Kerr int i, rc; 696d831f960SJeremy Kerr 6971a0e03b4SJeremy Kerr rc = 0; 6981a0e03b4SJeremy Kerr 699329a35f5SJeremy Kerr /* 700329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 701329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 702329a35f5SJeremy Kerr */ 703329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 704329a35f5SJeremy Kerr poller = console->pollers[i]; 705329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 7061cecc5deSJohnathan Mantey prc = POLLER_OK; 7071a0e03b4SJeremy Kerr 7081cecc5deSJohnathan Mantey /* process pending events... */ 7091cecc5deSJohnathan Mantey if (pollfd->revents) { 7101cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 711329a35f5SJeremy Kerr poller->data); 7122834c5b1SAndrew Jeffery if (prc == POLLER_EXIT) { 713329a35f5SJeremy Kerr rc = -1; 7142834c5b1SAndrew Jeffery } else if (prc == POLLER_REMOVE) { 715329a35f5SJeremy Kerr poller->remove = true; 716329a35f5SJeremy Kerr } 7172834c5b1SAndrew Jeffery } 718329a35f5SJeremy Kerr 7191cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 7201cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 7211cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 7221cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 7231cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 7241cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 7251cecc5deSJohnathan Mantey transmission. */ 7261cecc5deSJohnathan Mantey timerclear(&poller->timeout); 7271cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 7281cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 7291cecc5deSJohnathan Mantey rc = -1; 7301cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 7311cecc5deSJohnathan Mantey poller->remove = true; 7321cecc5deSJohnathan Mantey } 7331cecc5deSJohnathan Mantey } 7341cecc5deSJohnathan Mantey } 7351cecc5deSJohnathan Mantey 736329a35f5SJeremy Kerr /** 737329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 738329a35f5SJeremy Kerr * the array will have changed 739329a35f5SJeremy Kerr */ 740329a35f5SJeremy Kerr for (;;) { 741329a35f5SJeremy Kerr bool removed = false; 742329a35f5SJeremy Kerr 743329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 744329a35f5SJeremy Kerr poller = console->pollers[i]; 745329a35f5SJeremy Kerr if (poller->remove) { 74655c9712dSJeremy Kerr console_poller_unregister(console, poller); 747329a35f5SJeremy Kerr removed = true; 748329a35f5SJeremy Kerr break; 749329a35f5SJeremy Kerr } 750329a35f5SJeremy Kerr } 7512834c5b1SAndrew Jeffery if (!removed) { 752329a35f5SJeremy Kerr break; 7531a0e03b4SJeremy Kerr } 7542834c5b1SAndrew Jeffery } 7551a0e03b4SJeremy Kerr 7561a0e03b4SJeremy Kerr return rc; 7571a0e03b4SJeremy Kerr } 7581a0e03b4SJeremy Kerr 759769cee1aSJeremy Kerr static void sighandler(int signal) 760769cee1aSJeremy Kerr { 7612834c5b1SAndrew Jeffery if (signal == SIGINT) { 762769cee1aSJeremy Kerr sigint = true; 763769cee1aSJeremy Kerr } 7642834c5b1SAndrew Jeffery } 765769cee1aSJeremy Kerr 7661a0e03b4SJeremy Kerr int run_console(struct console *console) 7671a0e03b4SJeremy Kerr { 7685c359cc6SAndrew Jeffery sighandler_t sighandler_save = signal(SIGINT, sighandler); 7691cecc5deSJohnathan Mantey struct timeval tv; 7705c359cc6SAndrew Jeffery long timeout; 7715c359cc6SAndrew Jeffery ssize_t rc; 772769cee1aSJeremy Kerr 773769cee1aSJeremy Kerr rc = 0; 774769cee1aSJeremy Kerr 775d831f960SJeremy Kerr for (;;) { 776d831f960SJeremy Kerr uint8_t buf[4096]; 777d831f960SJeremy Kerr 7781764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7791764145dSJeremy Kerr 780769cee1aSJeremy Kerr if (sigint) { 781769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 782769cee1aSJeremy Kerr break; 783769cee1aSJeremy Kerr } 784769cee1aSJeremy Kerr 7851cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7861cecc5deSJohnathan Mantey if (rc) { 7871cecc5deSJohnathan Mantey warn("Failed to read current time"); 7881cecc5deSJohnathan Mantey break; 7891cecc5deSJohnathan Mantey } 7901cecc5deSJohnathan Mantey 7911cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7921cecc5deSJohnathan Mantey 793329a35f5SJeremy Kerr rc = poll(console->pollfds, 7945c359cc6SAndrew Jeffery console->n_pollers + MAX_INTERNAL_POLLFD, 7955c359cc6SAndrew Jeffery (int)timeout); 7961cecc5deSJohnathan Mantey 797d831f960SJeremy Kerr if (rc < 0) { 798769cee1aSJeremy Kerr if (errno == EINTR) { 799769cee1aSJeremy Kerr continue; 800*0b7b0477SAndrew Jeffery } 801d831f960SJeremy Kerr warn("poll error"); 802769cee1aSJeremy Kerr break; 803769cee1aSJeremy Kerr } 804d831f960SJeremy Kerr 805329a35f5SJeremy Kerr /* process internal fd first */ 806329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 8071a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 808d831f960SJeremy Kerr if (rc <= 0) { 809d831f960SJeremy Kerr warn("Error reading from tty device"); 810769cee1aSJeremy Kerr rc = -1; 811769cee1aSJeremy Kerr break; 812d831f960SJeremy Kerr } 813f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 8142834c5b1SAndrew Jeffery if (rc) { 815769cee1aSJeremy Kerr break; 816d831f960SJeremy Kerr } 8172834c5b1SAndrew Jeffery } 818d831f960SJeremy Kerr 819f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 820f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 821f9c8f6caSCheng C Yang } 822f9c8f6caSCheng C Yang 823329a35f5SJeremy Kerr /* ... and then the pollers */ 8241cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 8252834c5b1SAndrew Jeffery if (rc) { 826769cee1aSJeremy Kerr break; 8271a0e03b4SJeremy Kerr } 8282834c5b1SAndrew Jeffery } 829769cee1aSJeremy Kerr 830769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 831f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 832769cee1aSJeremy Kerr 833769cee1aSJeremy Kerr return rc ? -1 : 0; 8341a0e03b4SJeremy Kerr } 835d831f960SJeremy Kerr static const struct option options[] = { 836d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 837f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 838d831f960SJeremy Kerr }; 839d831f960SJeremy Kerr 840d831f960SJeremy Kerr int main(int argc, char **argv) 841d831f960SJeremy Kerr { 842d66195c1SJeremy Kerr const char *config_filename = NULL; 8436221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 8441a0e03b4SJeremy Kerr struct console *console; 845d66195c1SJeremy Kerr struct config *config; 846d66195c1SJeremy Kerr int rc; 847d831f960SJeremy Kerr 848957818b4SJeremy Kerr rc = -1; 849d831f960SJeremy Kerr 850d831f960SJeremy Kerr for (;;) { 851d831f960SJeremy Kerr int c, idx; 852d831f960SJeremy Kerr 853d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 8542834c5b1SAndrew Jeffery if (c == -1) { 855d831f960SJeremy Kerr break; 8562834c5b1SAndrew Jeffery } 857d831f960SJeremy Kerr 858d831f960SJeremy Kerr switch (c) { 859d66195c1SJeremy Kerr case 'c': 860d66195c1SJeremy Kerr config_filename = optarg; 861d831f960SJeremy Kerr break; 862d831f960SJeremy Kerr case 'h': 863d831f960SJeremy Kerr case '?': 864d831f960SJeremy Kerr usage(argv[0]); 865d66195c1SJeremy Kerr return EXIT_SUCCESS; 866d831f960SJeremy Kerr } 867d831f960SJeremy Kerr } 868d831f960SJeremy Kerr 8692834c5b1SAndrew Jeffery if (optind < argc) { 8706221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8712834c5b1SAndrew Jeffery } 8726221ce94SVishwanatha Subbanna 873d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 874d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 875a72711afSAndrew Jeffery console->pollfds = 876a72711afSAndrew Jeffery calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds)); 877f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 878329a35f5SJeremy Kerr 879d66195c1SJeremy Kerr config = config_init(config_filename); 880d66195c1SJeremy Kerr if (!config) { 881d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 882d66195c1SJeremy Kerr goto out_free; 883d831f960SJeremy Kerr } 884d831f960SJeremy Kerr 8852834c5b1SAndrew Jeffery if (!config_tty_kname) { 88691dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 8872834c5b1SAndrew Jeffery } 88891dde14eSAndrew Jeffery 88991dde14eSAndrew Jeffery if (!config_tty_kname) { 89091dde14eSAndrew Jeffery warnx("No TTY device specified"); 89191dde14eSAndrew Jeffery usage(argv[0]); 89291dde14eSAndrew Jeffery return EXIT_FAILURE; 89391dde14eSAndrew Jeffery } 89491dde14eSAndrew Jeffery 8956221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 8966221ce94SVishwanatha Subbanna 897d66195c1SJeremy Kerr rc = tty_init(console, config); 8982834c5b1SAndrew Jeffery if (rc) { 899d66195c1SJeremy Kerr goto out_config_fini; 9002834c5b1SAndrew Jeffery } 901d831f960SJeremy Kerr 902f9c8f6caSCheng C Yang dbus_init(console, config); 903f9c8f6caSCheng C Yang 904d47963e5SJeremy Kerr handlers_init(console, config); 905d831f960SJeremy Kerr 9061a0e03b4SJeremy Kerr rc = run_console(console); 907d831f960SJeremy Kerr 9081a0e03b4SJeremy Kerr handlers_fini(console); 909d831f960SJeremy Kerr 910d66195c1SJeremy Kerr out_config_fini: 911d66195c1SJeremy Kerr config_fini(config); 912d66195c1SJeremy Kerr 913957818b4SJeremy Kerr out_free: 91489ea8198SJeremy Kerr free(console->pollers); 91589ea8198SJeremy Kerr free(console->pollfds); 9161a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 9171a0e03b4SJeremy Kerr free(console->tty_dev); 9181a0e03b4SJeremy Kerr free(console); 919d831f960SJeremy Kerr 920d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 921d831f960SJeremy Kerr } 922