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; 243*b70f8713SAndrew Jeffery int i; 244*b70f8713SAndrew Jeffery int rc; 245f9c8f6caSCheng C Yang 246f9c8f6caSCheng C Yang tty_init_termios(console); 247f9c8f6caSCheng C Yang 248f9c8f6caSCheng C Yang for (i = 0; i < console->n_handlers; i++) { 249f9c8f6caSCheng C Yang handler = console->handlers[i]; 2502834c5b1SAndrew Jeffery if (!handler->baudrate) { 251f9c8f6caSCheng C Yang continue; 2522834c5b1SAndrew Jeffery } 253f9c8f6caSCheng C Yang 254f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 2552834c5b1SAndrew Jeffery if (rc) { 256f9c8f6caSCheng C Yang warnx("Can't set terminal baudrate for handler %s", 257f9c8f6caSCheng C Yang handler->name); 258f9c8f6caSCheng C Yang } 259f9c8f6caSCheng C Yang } 2602834c5b1SAndrew Jeffery } 261f9c8f6caSCheng C Yang 26254e9569dSJeremy Kerr /** 263d831f960SJeremy Kerr * Open and initialise the serial device 264d831f960SJeremy Kerr */ 2651a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 266d831f960SJeremy Kerr { 2672834c5b1SAndrew Jeffery if (console->tty_sirq) { 2681a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2692834c5b1SAndrew Jeffery } 2702834c5b1SAndrew Jeffery if (console->tty_lpc_addr) { 2711a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2721a0e03b4SJeremy Kerr console->tty_lpc_addr); 2732834c5b1SAndrew Jeffery } 274957818b4SJeremy Kerr 2751a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2761a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2771a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 278d831f960SJeremy Kerr return -1; 279d831f960SJeremy Kerr } 280d831f960SJeremy Kerr 281d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 282d831f960SJeremy Kerr * we detect larger amounts of data 283d831f960SJeremy Kerr */ 2841a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 285d831f960SJeremy Kerr 28654e9569dSJeremy Kerr tty_init_termios(console); 28754e9569dSJeremy Kerr 288329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 289329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 290329a35f5SJeremy Kerr 291d831f960SJeremy Kerr return 0; 292d831f960SJeremy Kerr } 293d831f960SJeremy Kerr 294d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 295d66195c1SJeremy Kerr { 296fd883a88SAndrew Jeffery unsigned long parsed; 297d66195c1SJeremy Kerr const char *val; 298d66195c1SJeremy Kerr char *endp; 299d66195c1SJeremy Kerr int rc; 300d66195c1SJeremy Kerr 301d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 302d66195c1SJeremy Kerr if (val) { 303fd883a88SAndrew Jeffery errno = 0; 304fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 305fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 306fd883a88SAndrew Jeffery warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'", 307fd883a88SAndrew Jeffery val); 308fd883a88SAndrew Jeffery return -1; 309fd883a88SAndrew Jeffery } 310fd883a88SAndrew Jeffery 311fd883a88SAndrew Jeffery if (parsed > UINT16_MAX) { 312fd883a88SAndrew Jeffery warn("Invalid LPC address '%s'", val); 313fd883a88SAndrew Jeffery return -1; 314fd883a88SAndrew Jeffery } 315fd883a88SAndrew Jeffery 316fd883a88SAndrew Jeffery console->tty_lpc_addr = (uint16_t)parsed; 317d66195c1SJeremy Kerr if (endp == optarg) { 318d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 319d66195c1SJeremy Kerr return -1; 320d66195c1SJeremy Kerr } 321d66195c1SJeremy Kerr } 322d66195c1SJeremy Kerr 323d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 324d66195c1SJeremy Kerr if (val) { 325fd883a88SAndrew Jeffery errno = 0; 326fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 327fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 328fd883a88SAndrew Jeffery warn("Cannot interpret 'sirq' value as an unsigned long: '%s'", 329fd883a88SAndrew Jeffery val); 330fd883a88SAndrew Jeffery } 331fd883a88SAndrew Jeffery 3322834c5b1SAndrew Jeffery if (parsed > 16) { 333fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 3342834c5b1SAndrew Jeffery } 335fd883a88SAndrew Jeffery 336fd883a88SAndrew Jeffery console->tty_sirq = (int)parsed; 3372834c5b1SAndrew Jeffery if (endp == optarg) { 338d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 339d66195c1SJeremy Kerr } 3402834c5b1SAndrew Jeffery } 341d66195c1SJeremy Kerr 342c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 343c7fbcd48SBenjamin Fair if (val) { 3442834c5b1SAndrew Jeffery if (config_parse_baud(&console->tty_baud, val)) { 345c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 346c7fbcd48SBenjamin Fair } 3472834c5b1SAndrew Jeffery } 348c7fbcd48SBenjamin Fair 349d66195c1SJeremy Kerr if (!console->tty_kname) { 350d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 351d66195c1SJeremy Kerr return -1; 352d66195c1SJeremy Kerr } 353d66195c1SJeremy Kerr 354d66195c1SJeremy Kerr rc = tty_find_device(console); 3552834c5b1SAndrew Jeffery if (rc) { 356d66195c1SJeremy Kerr return rc; 3572834c5b1SAndrew Jeffery } 358d66195c1SJeremy Kerr 359d66195c1SJeremy Kerr rc = tty_init_io(console); 360d66195c1SJeremy Kerr return rc; 361d66195c1SJeremy Kerr } 362d66195c1SJeremy Kerr 3631a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 364d831f960SJeremy Kerr { 3651a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 366d831f960SJeremy Kerr } 367d831f960SJeremy Kerr 368f9c8f6caSCheng C Yang static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 369f9c8f6caSCheng C Yang sd_bus_error *err) 370f9c8f6caSCheng C Yang { 371f9c8f6caSCheng C Yang struct console *console = userdata; 372f9c8f6caSCheng C Yang uint32_t baudrate; 373f9c8f6caSCheng C Yang speed_t speed; 374f9c8f6caSCheng C Yang int r; 375f9c8f6caSCheng C Yang 376f9c8f6caSCheng C Yang if (!console) { 377f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 378f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", 0); 379f9c8f6caSCheng C Yang } 380f9c8f6caSCheng C Yang 381f9c8f6caSCheng C Yang r = sd_bus_message_read(msg, "u", &baudrate); 382f9c8f6caSCheng C Yang if (r < 0) { 383f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 384f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 385f9c8f6caSCheng C Yang } 386f9c8f6caSCheng C Yang 387f9c8f6caSCheng C Yang speed = parse_int_to_baud(baudrate); 388f9c8f6caSCheng C Yang if (!speed) { 389f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%u'", baudrate); 390f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 391f9c8f6caSCheng C Yang } 392f9c8f6caSCheng C Yang 393f9c8f6caSCheng C Yang console->tty_baud = speed; 394f9c8f6caSCheng C Yang tty_change_baudrate(console); 395f9c8f6caSCheng C Yang 396f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", r); 397f9c8f6caSCheng C Yang } 398f9c8f6caSCheng C Yang 399fd048328SAndrew Jeffery static int get_handler(sd_bus *bus __attribute__((unused)), 400fd048328SAndrew Jeffery const char *path __attribute__((unused)), 401fd048328SAndrew Jeffery const char *interface __attribute__((unused)), 402fd048328SAndrew Jeffery const char *property __attribute__((unused)), 403fd048328SAndrew Jeffery sd_bus_message *reply, void *userdata, 404a72711afSAndrew Jeffery sd_bus_error *error __attribute__((unused))) 405a72711afSAndrew Jeffery { 406f9c8f6caSCheng C Yang struct console *console = userdata; 407f9c8f6caSCheng C Yang uint32_t baudrate; 408f9c8f6caSCheng C Yang int r; 409f9c8f6caSCheng C Yang 410f9c8f6caSCheng C Yang baudrate = parse_baud_to_int(console->tty_baud); 4112834c5b1SAndrew Jeffery if (!baudrate) { 412f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 4132834c5b1SAndrew Jeffery } 414f9c8f6caSCheng C Yang 415f9c8f6caSCheng C Yang r = sd_bus_message_append(reply, "u", baudrate); 416f9c8f6caSCheng C Yang 417f9c8f6caSCheng C Yang return r; 418f9c8f6caSCheng C Yang } 419f9c8f6caSCheng C Yang 420f9c8f6caSCheng C Yang static const sd_bus_vtable console_vtable[] = { 421f9c8f6caSCheng C Yang SD_BUS_VTABLE_START(0), 422f9c8f6caSCheng C Yang SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 423f9c8f6caSCheng C Yang SD_BUS_VTABLE_UNPRIVILEGED), 424f9c8f6caSCheng C Yang SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 425a72711afSAndrew Jeffery SD_BUS_VTABLE_END, 426a72711afSAndrew Jeffery }; 427f9c8f6caSCheng C Yang 428a72711afSAndrew Jeffery static void dbus_init(struct console *console, 429a72711afSAndrew Jeffery struct config *config __attribute__((unused))) 430f9c8f6caSCheng C Yang { 431f9c8f6caSCheng C Yang int dbus_poller = 0; 432*b70f8713SAndrew Jeffery int fd; 433*b70f8713SAndrew Jeffery int r; 434f9c8f6caSCheng C Yang 435f9c8f6caSCheng C Yang if (!console) { 436f9c8f6caSCheng C Yang warnx("Couldn't get valid console"); 437f9c8f6caSCheng C Yang return; 438f9c8f6caSCheng C Yang } 439f9c8f6caSCheng C Yang 440f9c8f6caSCheng C Yang r = sd_bus_default_system(&console->bus); 441f9c8f6caSCheng C Yang if (r < 0) { 442f9c8f6caSCheng C Yang warnx("Failed to connect to system bus: %s", strerror(-r)); 443f9c8f6caSCheng C Yang return; 444f9c8f6caSCheng C Yang } 445f9c8f6caSCheng C Yang 446f9c8f6caSCheng C Yang r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 447f9c8f6caSCheng C Yang console_vtable, console); 448f9c8f6caSCheng C Yang if (r < 0) { 449f9c8f6caSCheng C Yang warnx("Failed to issue method call: %s", strerror(-r)); 450f9c8f6caSCheng C Yang return; 451f9c8f6caSCheng C Yang } 452f9c8f6caSCheng C Yang 453a72711afSAndrew Jeffery r = sd_bus_request_name(console->bus, DBUS_NAME, 454a72711afSAndrew Jeffery SD_BUS_NAME_ALLOW_REPLACEMENT | 455a72711afSAndrew Jeffery SD_BUS_NAME_REPLACE_EXISTING); 456f9c8f6caSCheng C Yang if (r < 0) { 457f9c8f6caSCheng C Yang warnx("Failed to acquire service name: %s", strerror(-r)); 458f9c8f6caSCheng C Yang return; 459f9c8f6caSCheng C Yang } 460f9c8f6caSCheng C Yang 461f9c8f6caSCheng C Yang fd = sd_bus_get_fd(console->bus); 462f9c8f6caSCheng C Yang if (fd < 0) { 463f9c8f6caSCheng C Yang warnx("Couldn't get the bus file descriptor"); 464f9c8f6caSCheng C Yang return; 465f9c8f6caSCheng C Yang } 466f9c8f6caSCheng C Yang 467f9c8f6caSCheng C Yang dbus_poller = POLLFD_DBUS; 468f9c8f6caSCheng C Yang 469f9c8f6caSCheng C Yang console->pollfds[dbus_poller].fd = fd; 470f9c8f6caSCheng C Yang console->pollfds[dbus_poller].events = POLLIN; 471f9c8f6caSCheng C Yang } 472f9c8f6caSCheng C Yang 473d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 474d831f960SJeremy Kerr { 475*b70f8713SAndrew Jeffery /* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 476*b70f8713SAndrew Jeffery extern struct handler *__start_handlers; 477*b70f8713SAndrew Jeffery extern struct handler *__stop_handlers; 478*b70f8713SAndrew Jeffery /* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 4791a0e03b4SJeremy Kerr struct handler *handler; 480*b70f8713SAndrew Jeffery int i; 481*b70f8713SAndrew Jeffery int rc; 482d831f960SJeremy Kerr 4831a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4841a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 485d831f960SJeremy Kerr 4865c359cc6SAndrew Jeffery printf("%ld handler%s\n", console->n_handlers, 4871a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 488d831f960SJeremy Kerr 4891a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4901a0e03b4SJeremy Kerr handler = console->handlers[i]; 4911a0e03b4SJeremy Kerr 492021b91f0SJeremy Kerr rc = 0; 4932834c5b1SAndrew Jeffery if (handler->init) { 494021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 4952834c5b1SAndrew Jeffery } 496021b91f0SJeremy Kerr 497021b91f0SJeremy Kerr handler->active = rc == 0; 498021b91f0SJeremy Kerr 499021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 500021b91f0SJeremy Kerr handler->active ? "" : "in"); 501d831f960SJeremy Kerr } 502d831f960SJeremy Kerr } 503d831f960SJeremy Kerr 5041a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 505d831f960SJeremy Kerr { 5061a0e03b4SJeremy Kerr struct handler *handler; 5071a0e03b4SJeremy Kerr int i; 5081a0e03b4SJeremy Kerr 5091a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 5101a0e03b4SJeremy Kerr handler = console->handlers[i]; 5112834c5b1SAndrew Jeffery if (handler->fini && handler->active) { 5121a0e03b4SJeremy Kerr handler->fini(handler); 5131a0e03b4SJeremy Kerr } 514d831f960SJeremy Kerr } 5152834c5b1SAndrew Jeffery } 516d831f960SJeremy Kerr 5171cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 5181cecc5deSJohnathan Mantey { 5191cecc5deSJohnathan Mantey struct timespec t; 5201cecc5deSJohnathan Mantey int rc; 5211cecc5deSJohnathan Mantey 5221cecc5deSJohnathan Mantey /* 5231cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 5241cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 5251cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 5261cecc5deSJohnathan Mantey */ 5271cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 5282834c5b1SAndrew Jeffery if (rc) { 5291cecc5deSJohnathan Mantey return rc; 5302834c5b1SAndrew Jeffery } 5311cecc5deSJohnathan Mantey 5321cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 5331cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 5341cecc5deSJohnathan Mantey 5351cecc5deSJohnathan Mantey return 0; 5361cecc5deSJohnathan Mantey } 5371cecc5deSJohnathan Mantey 538a72711afSAndrew Jeffery struct ringbuffer_consumer * 539a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console, 540f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 541d831f960SJeremy Kerr { 542f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 543d831f960SJeremy Kerr } 544d831f960SJeremy Kerr 54555c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 546a72711afSAndrew Jeffery struct handler *handler, 547a72711afSAndrew Jeffery poller_event_fn_t poller_fn, 5481cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 5491cecc5deSJohnathan Mantey int events, void *data) 550d831f960SJeremy Kerr { 551329a35f5SJeremy Kerr struct poller *poller; 5525c359cc6SAndrew Jeffery long n; 553329a35f5SJeremy Kerr 554329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 555329a35f5SJeremy Kerr poller->remove = false; 556329a35f5SJeremy Kerr poller->handler = handler; 5571cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5581cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 559329a35f5SJeremy Kerr poller->data = data; 560329a35f5SJeremy Kerr 561329a35f5SJeremy Kerr /* add one to our pollers array */ 562329a35f5SJeremy Kerr n = console->n_pollers++; 56391b52175SAndrew Jeffery /* 56491b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 56591b52175SAndrew Jeffery * pointer type. 56691b52175SAndrew Jeffery */ 56791b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 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 console->pollers[n] = poller; 573329a35f5SJeremy Kerr 574329a35f5SJeremy Kerr /* increase pollfds array too */ 575a72711afSAndrew Jeffery console->pollfds = 57691b52175SAndrew Jeffery reallocarray(console->pollfds, 57791b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 57891b52175SAndrew Jeffery sizeof(*console->pollfds)); 579329a35f5SJeremy Kerr 580329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 581a72711afSAndrew Jeffery memcpy(&console->pollfds[n + 1], &console->pollfds[n], 582f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 583329a35f5SJeremy Kerr 584329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 5855c359cc6SAndrew Jeffery console->pollfds[n].events = (short)(events & 0x7fff); 586329a35f5SJeremy Kerr 587329a35f5SJeremy Kerr return poller; 588329a35f5SJeremy Kerr } 589329a35f5SJeremy Kerr 590a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller) 591329a35f5SJeremy Kerr { 592329a35f5SJeremy Kerr int i; 593329a35f5SJeremy Kerr 594329a35f5SJeremy Kerr /* find the entry in our pollers array */ 5952834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 5962834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 597329a35f5SJeremy Kerr break; 5982834c5b1SAndrew Jeffery } 5992834c5b1SAndrew Jeffery } 600329a35f5SJeremy Kerr 601329a35f5SJeremy Kerr assert(i < console->n_pollers); 602329a35f5SJeremy Kerr 603329a35f5SJeremy Kerr console->n_pollers--; 604329a35f5SJeremy Kerr 60591b52175SAndrew Jeffery /* 60691b52175SAndrew Jeffery * Remove the item from the pollers array... 60791b52175SAndrew Jeffery * 60891b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 60991b52175SAndrew Jeffery * pointer type. 61091b52175SAndrew Jeffery */ 61191b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 612329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i + 1], 613a72711afSAndrew Jeffery sizeof(*console->pollers) * (console->n_pollers - i)); 614329a35f5SJeremy Kerr 61591b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 61691b52175SAndrew Jeffery sizeof(*console->pollers)); 61791b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 618329a35f5SJeremy Kerr 619329a35f5SJeremy Kerr /* ... and the pollfds array */ 620329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i + 1], 621329a35f5SJeremy Kerr sizeof(*console->pollfds) * 622f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 623329a35f5SJeremy Kerr 624a72711afSAndrew Jeffery console->pollfds = 62591b52175SAndrew Jeffery reallocarray(console->pollfds, 62691b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 62791b52175SAndrew Jeffery sizeof(*console->pollfds)); 628329a35f5SJeremy Kerr 629329a35f5SJeremy Kerr free(poller); 630329a35f5SJeremy Kerr } 631329a35f5SJeremy Kerr 6326b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 6336b1fed27SJeremy Kerr int events) 6346b1fed27SJeremy Kerr { 6356b1fed27SJeremy Kerr int i; 6366b1fed27SJeremy Kerr 6376b1fed27SJeremy Kerr /* find the entry in our pollers array */ 6382834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 6392834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 6406b1fed27SJeremy Kerr break; 6412834c5b1SAndrew Jeffery } 6422834c5b1SAndrew Jeffery } 6436b1fed27SJeremy Kerr 6445c359cc6SAndrew Jeffery console->pollfds[i].events = (short)(events & 0x7fff); 6456b1fed27SJeremy Kerr } 6466b1fed27SJeremy Kerr 647fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 648fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 6491cecc5deSJohnathan Mantey { 6501cecc5deSJohnathan Mantey struct timeval now; 6511cecc5deSJohnathan Mantey int rc; 6521cecc5deSJohnathan Mantey 6531cecc5deSJohnathan Mantey rc = get_current_time(&now); 6542834c5b1SAndrew Jeffery if (rc) { 6551cecc5deSJohnathan Mantey return; 6562834c5b1SAndrew Jeffery } 6571cecc5deSJohnathan Mantey 6581cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 6591cecc5deSJohnathan Mantey } 6601cecc5deSJohnathan Mantey 6615c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time) 6621cecc5deSJohnathan Mantey { 663*b70f8713SAndrew Jeffery struct timeval *earliest; 664*b70f8713SAndrew Jeffery struct timeval interval; 6651cecc5deSJohnathan Mantey struct poller *poller; 6661cecc5deSJohnathan Mantey int i; 6671cecc5deSJohnathan Mantey 6681cecc5deSJohnathan Mantey earliest = NULL; 6691cecc5deSJohnathan Mantey 6701cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 6711cecc5deSJohnathan Mantey poller = console->pollers[i]; 6721cecc5deSJohnathan Mantey 6731cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6741cecc5deSJohnathan Mantey (!earliest || 6751cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))) { 6761cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6771cecc5deSJohnathan Mantey // function to timeout. 6781cecc5deSJohnathan Mantey earliest = &poller->timeout; 6791cecc5deSJohnathan Mantey } 6801cecc5deSJohnathan Mantey } 6811cecc5deSJohnathan Mantey 6821cecc5deSJohnathan Mantey if (earliest) { 6831cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6841cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6851cecc5deSJohnathan Mantey * not elapsed */ 6861cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6871cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6881cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 6890b7b0477SAndrew Jeffery } /* return from poll immediately */ 6901cecc5deSJohnathan Mantey return 0; 6910b7b0477SAndrew Jeffery 6920b7b0477SAndrew Jeffery } /* poll indefinitely */ 6931cecc5deSJohnathan Mantey return -1; 6941cecc5deSJohnathan Mantey } 6951cecc5deSJohnathan Mantey 6961cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 697329a35f5SJeremy Kerr { 698329a35f5SJeremy Kerr struct poller *poller; 699329a35f5SJeremy Kerr struct pollfd *pollfd; 700329a35f5SJeremy Kerr enum poller_ret prc; 701*b70f8713SAndrew Jeffery int i; 702*b70f8713SAndrew Jeffery int rc; 703d831f960SJeremy Kerr 7041a0e03b4SJeremy Kerr rc = 0; 7051a0e03b4SJeremy Kerr 706329a35f5SJeremy Kerr /* 707329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 708329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 709329a35f5SJeremy Kerr */ 710329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 711329a35f5SJeremy Kerr poller = console->pollers[i]; 712329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 7131cecc5deSJohnathan Mantey prc = POLLER_OK; 7141a0e03b4SJeremy Kerr 7151cecc5deSJohnathan Mantey /* process pending events... */ 7161cecc5deSJohnathan Mantey if (pollfd->revents) { 7171cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 718329a35f5SJeremy Kerr poller->data); 7192834c5b1SAndrew Jeffery if (prc == POLLER_EXIT) { 720329a35f5SJeremy Kerr rc = -1; 7212834c5b1SAndrew Jeffery } else if (prc == POLLER_REMOVE) { 722329a35f5SJeremy Kerr poller->remove = true; 723329a35f5SJeremy Kerr } 7242834c5b1SAndrew Jeffery } 725329a35f5SJeremy Kerr 7261cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 7271cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 7281cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 7291cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 7301cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 7311cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 7321cecc5deSJohnathan Mantey transmission. */ 7331cecc5deSJohnathan Mantey timerclear(&poller->timeout); 7341cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 7351cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 7361cecc5deSJohnathan Mantey rc = -1; 7371cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 7381cecc5deSJohnathan Mantey poller->remove = true; 7391cecc5deSJohnathan Mantey } 7401cecc5deSJohnathan Mantey } 7411cecc5deSJohnathan Mantey } 7421cecc5deSJohnathan Mantey 743329a35f5SJeremy Kerr /** 744329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 745329a35f5SJeremy Kerr * the array will have changed 746329a35f5SJeremy Kerr */ 747329a35f5SJeremy Kerr for (;;) { 748329a35f5SJeremy Kerr bool removed = false; 749329a35f5SJeremy Kerr 750329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 751329a35f5SJeremy Kerr poller = console->pollers[i]; 752329a35f5SJeremy Kerr if (poller->remove) { 75355c9712dSJeremy Kerr console_poller_unregister(console, poller); 754329a35f5SJeremy Kerr removed = true; 755329a35f5SJeremy Kerr break; 756329a35f5SJeremy Kerr } 757329a35f5SJeremy Kerr } 7582834c5b1SAndrew Jeffery if (!removed) { 759329a35f5SJeremy Kerr break; 7601a0e03b4SJeremy Kerr } 7612834c5b1SAndrew Jeffery } 7621a0e03b4SJeremy Kerr 7631a0e03b4SJeremy Kerr return rc; 7641a0e03b4SJeremy Kerr } 7651a0e03b4SJeremy Kerr 766769cee1aSJeremy Kerr static void sighandler(int signal) 767769cee1aSJeremy Kerr { 7682834c5b1SAndrew Jeffery if (signal == SIGINT) { 769769cee1aSJeremy Kerr sigint = true; 770769cee1aSJeremy Kerr } 7712834c5b1SAndrew Jeffery } 772769cee1aSJeremy Kerr 7731a0e03b4SJeremy Kerr int run_console(struct console *console) 7741a0e03b4SJeremy Kerr { 7755c359cc6SAndrew Jeffery sighandler_t sighandler_save = signal(SIGINT, sighandler); 7761cecc5deSJohnathan Mantey struct timeval tv; 7775c359cc6SAndrew Jeffery long timeout; 7785c359cc6SAndrew Jeffery ssize_t rc; 779769cee1aSJeremy Kerr 780769cee1aSJeremy Kerr rc = 0; 781769cee1aSJeremy Kerr 782d831f960SJeremy Kerr for (;;) { 783d831f960SJeremy Kerr uint8_t buf[4096]; 784d831f960SJeremy Kerr 7851764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7861764145dSJeremy Kerr 787769cee1aSJeremy Kerr if (sigint) { 788769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 789769cee1aSJeremy Kerr break; 790769cee1aSJeremy Kerr } 791769cee1aSJeremy Kerr 7921cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7931cecc5deSJohnathan Mantey if (rc) { 7941cecc5deSJohnathan Mantey warn("Failed to read current time"); 7951cecc5deSJohnathan Mantey break; 7961cecc5deSJohnathan Mantey } 7971cecc5deSJohnathan Mantey 7981cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7991cecc5deSJohnathan Mantey 800329a35f5SJeremy Kerr rc = poll(console->pollfds, 8015c359cc6SAndrew Jeffery console->n_pollers + MAX_INTERNAL_POLLFD, 8025c359cc6SAndrew Jeffery (int)timeout); 8031cecc5deSJohnathan Mantey 804d831f960SJeremy Kerr if (rc < 0) { 805769cee1aSJeremy Kerr if (errno == EINTR) { 806769cee1aSJeremy Kerr continue; 8070b7b0477SAndrew Jeffery } 808d831f960SJeremy Kerr warn("poll error"); 809769cee1aSJeremy Kerr break; 810769cee1aSJeremy Kerr } 811d831f960SJeremy Kerr 812329a35f5SJeremy Kerr /* process internal fd first */ 813329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 8141a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 815d831f960SJeremy Kerr if (rc <= 0) { 816d831f960SJeremy Kerr warn("Error reading from tty device"); 817769cee1aSJeremy Kerr rc = -1; 818769cee1aSJeremy Kerr break; 819d831f960SJeremy Kerr } 820f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 8212834c5b1SAndrew Jeffery if (rc) { 822769cee1aSJeremy Kerr break; 823d831f960SJeremy Kerr } 8242834c5b1SAndrew Jeffery } 825d831f960SJeremy Kerr 826f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 827f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 828f9c8f6caSCheng C Yang } 829f9c8f6caSCheng C Yang 830329a35f5SJeremy Kerr /* ... and then the pollers */ 8311cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 8322834c5b1SAndrew Jeffery if (rc) { 833769cee1aSJeremy Kerr break; 8341a0e03b4SJeremy Kerr } 8352834c5b1SAndrew Jeffery } 836769cee1aSJeremy Kerr 837769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 838f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 839769cee1aSJeremy Kerr 840769cee1aSJeremy Kerr return rc ? -1 : 0; 8411a0e03b4SJeremy Kerr } 842d831f960SJeremy Kerr static const struct option options[] = { 843d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 844f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 845d831f960SJeremy Kerr }; 846d831f960SJeremy Kerr 847d831f960SJeremy Kerr int main(int argc, char **argv) 848d831f960SJeremy Kerr { 849d66195c1SJeremy Kerr const char *config_filename = NULL; 8506221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 8511a0e03b4SJeremy Kerr struct console *console; 852d66195c1SJeremy Kerr struct config *config; 853d66195c1SJeremy Kerr int rc; 854d831f960SJeremy Kerr 855957818b4SJeremy Kerr rc = -1; 856d831f960SJeremy Kerr 857d831f960SJeremy Kerr for (;;) { 858*b70f8713SAndrew Jeffery int c; 859*b70f8713SAndrew Jeffery int idx; 860d831f960SJeremy Kerr 861d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 8622834c5b1SAndrew Jeffery if (c == -1) { 863d831f960SJeremy Kerr break; 8642834c5b1SAndrew Jeffery } 865d831f960SJeremy Kerr 866d831f960SJeremy Kerr switch (c) { 867d66195c1SJeremy Kerr case 'c': 868d66195c1SJeremy Kerr config_filename = optarg; 869d831f960SJeremy Kerr break; 870d831f960SJeremy Kerr case 'h': 871d831f960SJeremy Kerr case '?': 872d831f960SJeremy Kerr usage(argv[0]); 873d66195c1SJeremy Kerr return EXIT_SUCCESS; 874d831f960SJeremy Kerr } 875d831f960SJeremy Kerr } 876d831f960SJeremy Kerr 8772834c5b1SAndrew Jeffery if (optind < argc) { 8786221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8792834c5b1SAndrew Jeffery } 8806221ce94SVishwanatha Subbanna 881d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 882d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 883a72711afSAndrew Jeffery console->pollfds = 884a72711afSAndrew Jeffery calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds)); 885f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 886329a35f5SJeremy Kerr 887d66195c1SJeremy Kerr config = config_init(config_filename); 888d66195c1SJeremy Kerr if (!config) { 889d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 890d66195c1SJeremy Kerr goto out_free; 891d831f960SJeremy Kerr } 892d831f960SJeremy Kerr 8932834c5b1SAndrew Jeffery if (!config_tty_kname) { 89491dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 8952834c5b1SAndrew Jeffery } 89691dde14eSAndrew Jeffery 89791dde14eSAndrew Jeffery if (!config_tty_kname) { 89891dde14eSAndrew Jeffery warnx("No TTY device specified"); 89991dde14eSAndrew Jeffery usage(argv[0]); 90091dde14eSAndrew Jeffery return EXIT_FAILURE; 90191dde14eSAndrew Jeffery } 90291dde14eSAndrew Jeffery 9036221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 9046221ce94SVishwanatha Subbanna 905d66195c1SJeremy Kerr rc = tty_init(console, config); 9062834c5b1SAndrew Jeffery if (rc) { 907d66195c1SJeremy Kerr goto out_config_fini; 9082834c5b1SAndrew Jeffery } 909d831f960SJeremy Kerr 910f9c8f6caSCheng C Yang dbus_init(console, config); 911f9c8f6caSCheng C Yang 912d47963e5SJeremy Kerr handlers_init(console, config); 913d831f960SJeremy Kerr 9141a0e03b4SJeremy Kerr rc = run_console(console); 915d831f960SJeremy Kerr 9161a0e03b4SJeremy Kerr handlers_fini(console); 917d831f960SJeremy Kerr 918d66195c1SJeremy Kerr out_config_fini: 919d66195c1SJeremy Kerr config_fini(config); 920d66195c1SJeremy Kerr 921957818b4SJeremy Kerr out_free: 92289ea8198SJeremy Kerr free(console->pollers); 92389ea8198SJeremy Kerr free(console->pollfds); 9241a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 9251a0e03b4SJeremy Kerr free(console->tty_dev); 9261a0e03b4SJeremy Kerr free(console); 927d831f960SJeremy Kerr 928d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 929d831f960SJeremy Kerr } 930