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); 119*2834c5b1SAndrew Jeffery if (rc < 0) { 12017217845SJeremy Kerr return -1; 121*2834c5b1SAndrew 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); 139*2834c5b1SAndrew Jeffery if (rc < 0) { 14045ad7676SYi Li goto out_free; 141*2834c5b1SAndrew 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); 151*2834c5b1SAndrew Jeffery if (rc < 0) { 15217217845SJeremy Kerr goto out_free; 153*2834c5b1SAndrew Jeffery } 15417217845SJeremy Kerr 1551a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 156*2834c5b1SAndrew Jeffery if (!console->tty_sysfs_devnode) { 15745ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 158*2834c5b1SAndrew Jeffery } 15917217845SJeremy Kerr 16045ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 161*2834c5b1SAndrew Jeffery if (rc < 0) { 16217217845SJeremy Kerr goto out_free; 163*2834c5b1SAndrew 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); 184*2834c5b1SAndrew Jeffery if (rc < 0) { 185957818b4SJeremy Kerr return -1; 186*2834c5b1SAndrew 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); 198*2834c5b1SAndrew Jeffery if (rc < 0) { 199a72711afSAndrew Jeffery warn("Error writing to %s attribute of device %s", name, 200a72711afSAndrew Jeffery console->tty_kname); 201*2834c5b1SAndrew 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) { 224*2834c5b1SAndrew Jeffery if (cfsetspeed(&termios, console->tty_baud) < 0) { 225c7fbcd48SBenjamin Fair warn("Couldn't set speeds for %s", console->tty_kname); 226c7fbcd48SBenjamin Fair } 227*2834c5b1SAndrew 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); 235*2834c5b1SAndrew Jeffery if (rc) { 236c7fbcd48SBenjamin Fair warn("Can't set terminal options for %s", console->tty_kname); 23754e9569dSJeremy Kerr } 238*2834c5b1SAndrew 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]; 249*2834c5b1SAndrew Jeffery if (!handler->baudrate) { 250f9c8f6caSCheng C Yang continue; 251*2834c5b1SAndrew Jeffery } 252f9c8f6caSCheng C Yang 253f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 254*2834c5b1SAndrew 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 } 259*2834c5b1SAndrew 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 { 266*2834c5b1SAndrew Jeffery if (console->tty_sirq) { 2671a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 268*2834c5b1SAndrew Jeffery } 269*2834c5b1SAndrew Jeffery if (console->tty_lpc_addr) { 2701a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2711a0e03b4SJeremy Kerr console->tty_lpc_addr); 272*2834c5b1SAndrew 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 331*2834c5b1SAndrew Jeffery if (parsed > 16) { 332fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 333*2834c5b1SAndrew Jeffery } 334fd883a88SAndrew Jeffery 335fd883a88SAndrew Jeffery console->tty_sirq = (int)parsed; 336*2834c5b1SAndrew Jeffery if (endp == optarg) { 337d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 338d66195c1SJeremy Kerr } 339*2834c5b1SAndrew Jeffery } 340d66195c1SJeremy Kerr 341c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 342c7fbcd48SBenjamin Fair if (val) { 343*2834c5b1SAndrew Jeffery if (config_parse_baud(&console->tty_baud, val)) { 344c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 345c7fbcd48SBenjamin Fair } 346*2834c5b1SAndrew 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); 354*2834c5b1SAndrew Jeffery if (rc) { 355d66195c1SJeremy Kerr return rc; 356*2834c5b1SAndrew 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); 410*2834c5b1SAndrew Jeffery if (!baudrate) { 411f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 412*2834c5b1SAndrew 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; 488*2834c5b1SAndrew Jeffery if (handler->init) { 489021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 490*2834c5b1SAndrew 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]; 506*2834c5b1SAndrew Jeffery if (handler->fini && handler->active) { 5071a0e03b4SJeremy Kerr handler->fini(handler); 5081a0e03b4SJeremy Kerr } 509d831f960SJeremy Kerr } 510*2834c5b1SAndrew 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); 523*2834c5b1SAndrew Jeffery if (rc) { 5241cecc5deSJohnathan Mantey return rc; 525*2834c5b1SAndrew 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 */ 590*2834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 591*2834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 592329a35f5SJeremy Kerr break; 593*2834c5b1SAndrew Jeffery } 594*2834c5b1SAndrew 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 */ 633*2834c5b1SAndrew Jeffery for (i = 0; i < console->n_pollers; i++) { 634*2834c5b1SAndrew Jeffery if (console->pollers[i] == poller) { 6356b1fed27SJeremy Kerr break; 636*2834c5b1SAndrew Jeffery } 637*2834c5b1SAndrew 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); 649*2834c5b1SAndrew Jeffery if (rc) { 6501cecc5deSJohnathan Mantey return; 651*2834c5b1SAndrew 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)); 6831cecc5deSJohnathan Mantey } else { 6841cecc5deSJohnathan Mantey /* return from poll immediately */ 6851cecc5deSJohnathan Mantey return 0; 6861cecc5deSJohnathan Mantey } 6871cecc5deSJohnathan Mantey } else { 6881cecc5deSJohnathan Mantey /* poll indefinitely */ 6891cecc5deSJohnathan Mantey return -1; 6901cecc5deSJohnathan Mantey } 6911cecc5deSJohnathan Mantey } 6921cecc5deSJohnathan Mantey 6931cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 694329a35f5SJeremy Kerr { 695329a35f5SJeremy Kerr struct poller *poller; 696329a35f5SJeremy Kerr struct pollfd *pollfd; 697329a35f5SJeremy Kerr enum poller_ret prc; 698329a35f5SJeremy Kerr int i, rc; 699d831f960SJeremy Kerr 7001a0e03b4SJeremy Kerr rc = 0; 7011a0e03b4SJeremy Kerr 702329a35f5SJeremy Kerr /* 703329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 704329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 705329a35f5SJeremy Kerr */ 706329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 707329a35f5SJeremy Kerr poller = console->pollers[i]; 708329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 7091cecc5deSJohnathan Mantey prc = POLLER_OK; 7101a0e03b4SJeremy Kerr 7111cecc5deSJohnathan Mantey /* process pending events... */ 7121cecc5deSJohnathan Mantey if (pollfd->revents) { 7131cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 714329a35f5SJeremy Kerr poller->data); 715*2834c5b1SAndrew Jeffery if (prc == POLLER_EXIT) { 716329a35f5SJeremy Kerr rc = -1; 717*2834c5b1SAndrew Jeffery } else if (prc == POLLER_REMOVE) { 718329a35f5SJeremy Kerr poller->remove = true; 719329a35f5SJeremy Kerr } 720*2834c5b1SAndrew Jeffery } 721329a35f5SJeremy Kerr 7221cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 7231cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 7241cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 7251cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 7261cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 7271cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 7281cecc5deSJohnathan Mantey transmission. */ 7291cecc5deSJohnathan Mantey timerclear(&poller->timeout); 7301cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 7311cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 7321cecc5deSJohnathan Mantey rc = -1; 7331cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 7341cecc5deSJohnathan Mantey poller->remove = true; 7351cecc5deSJohnathan Mantey } 7361cecc5deSJohnathan Mantey } 7371cecc5deSJohnathan Mantey } 7381cecc5deSJohnathan Mantey 739329a35f5SJeremy Kerr /** 740329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 741329a35f5SJeremy Kerr * the array will have changed 742329a35f5SJeremy Kerr */ 743329a35f5SJeremy Kerr for (;;) { 744329a35f5SJeremy Kerr bool removed = false; 745329a35f5SJeremy Kerr 746329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 747329a35f5SJeremy Kerr poller = console->pollers[i]; 748329a35f5SJeremy Kerr if (poller->remove) { 74955c9712dSJeremy Kerr console_poller_unregister(console, poller); 750329a35f5SJeremy Kerr removed = true; 751329a35f5SJeremy Kerr break; 752329a35f5SJeremy Kerr } 753329a35f5SJeremy Kerr } 754*2834c5b1SAndrew Jeffery if (!removed) { 755329a35f5SJeremy Kerr break; 7561a0e03b4SJeremy Kerr } 757*2834c5b1SAndrew Jeffery } 7581a0e03b4SJeremy Kerr 7591a0e03b4SJeremy Kerr return rc; 7601a0e03b4SJeremy Kerr } 7611a0e03b4SJeremy Kerr 762769cee1aSJeremy Kerr static void sighandler(int signal) 763769cee1aSJeremy Kerr { 764*2834c5b1SAndrew Jeffery if (signal == SIGINT) { 765769cee1aSJeremy Kerr sigint = true; 766769cee1aSJeremy Kerr } 767*2834c5b1SAndrew Jeffery } 768769cee1aSJeremy Kerr 7691a0e03b4SJeremy Kerr int run_console(struct console *console) 7701a0e03b4SJeremy Kerr { 7715c359cc6SAndrew Jeffery sighandler_t sighandler_save = signal(SIGINT, sighandler); 7721cecc5deSJohnathan Mantey struct timeval tv; 7735c359cc6SAndrew Jeffery long timeout; 7745c359cc6SAndrew Jeffery ssize_t rc; 775769cee1aSJeremy Kerr 776769cee1aSJeremy Kerr rc = 0; 777769cee1aSJeremy Kerr 778d831f960SJeremy Kerr for (;;) { 779d831f960SJeremy Kerr uint8_t buf[4096]; 780d831f960SJeremy Kerr 7811764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7821764145dSJeremy Kerr 783769cee1aSJeremy Kerr if (sigint) { 784769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 785769cee1aSJeremy Kerr break; 786769cee1aSJeremy Kerr } 787769cee1aSJeremy Kerr 7881cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7891cecc5deSJohnathan Mantey if (rc) { 7901cecc5deSJohnathan Mantey warn("Failed to read current time"); 7911cecc5deSJohnathan Mantey break; 7921cecc5deSJohnathan Mantey } 7931cecc5deSJohnathan Mantey 7941cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7951cecc5deSJohnathan Mantey 796329a35f5SJeremy Kerr rc = poll(console->pollfds, 7975c359cc6SAndrew Jeffery console->n_pollers + MAX_INTERNAL_POLLFD, 7985c359cc6SAndrew Jeffery (int)timeout); 7991cecc5deSJohnathan Mantey 800d831f960SJeremy Kerr if (rc < 0) { 801769cee1aSJeremy Kerr if (errno == EINTR) { 802769cee1aSJeremy Kerr continue; 803769cee1aSJeremy Kerr } else { 804d831f960SJeremy Kerr warn("poll error"); 805769cee1aSJeremy Kerr break; 806769cee1aSJeremy Kerr } 807d831f960SJeremy Kerr } 808d831f960SJeremy Kerr 809329a35f5SJeremy Kerr /* process internal fd first */ 810329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 8111a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 812d831f960SJeremy Kerr if (rc <= 0) { 813d831f960SJeremy Kerr warn("Error reading from tty device"); 814769cee1aSJeremy Kerr rc = -1; 815769cee1aSJeremy Kerr break; 816d831f960SJeremy Kerr } 817f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 818*2834c5b1SAndrew Jeffery if (rc) { 819769cee1aSJeremy Kerr break; 820d831f960SJeremy Kerr } 821*2834c5b1SAndrew Jeffery } 822d831f960SJeremy Kerr 823f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 824f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 825f9c8f6caSCheng C Yang } 826f9c8f6caSCheng C Yang 827329a35f5SJeremy Kerr /* ... and then the pollers */ 8281cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 829*2834c5b1SAndrew Jeffery if (rc) { 830769cee1aSJeremy Kerr break; 8311a0e03b4SJeremy Kerr } 832*2834c5b1SAndrew Jeffery } 833769cee1aSJeremy Kerr 834769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 835f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 836769cee1aSJeremy Kerr 837769cee1aSJeremy Kerr return rc ? -1 : 0; 8381a0e03b4SJeremy Kerr } 839d831f960SJeremy Kerr static const struct option options[] = { 840d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 841f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 842d831f960SJeremy Kerr }; 843d831f960SJeremy Kerr 844d831f960SJeremy Kerr int main(int argc, char **argv) 845d831f960SJeremy Kerr { 846d66195c1SJeremy Kerr const char *config_filename = NULL; 8476221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 8481a0e03b4SJeremy Kerr struct console *console; 849d66195c1SJeremy Kerr struct config *config; 850d66195c1SJeremy Kerr int rc; 851d831f960SJeremy Kerr 852957818b4SJeremy Kerr rc = -1; 853d831f960SJeremy Kerr 854d831f960SJeremy Kerr for (;;) { 855d831f960SJeremy Kerr int c, idx; 856d831f960SJeremy Kerr 857d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 858*2834c5b1SAndrew Jeffery if (c == -1) { 859d831f960SJeremy Kerr break; 860*2834c5b1SAndrew Jeffery } 861d831f960SJeremy Kerr 862d831f960SJeremy Kerr switch (c) { 863d66195c1SJeremy Kerr case 'c': 864d66195c1SJeremy Kerr config_filename = optarg; 865d831f960SJeremy Kerr break; 866d831f960SJeremy Kerr case 'h': 867d831f960SJeremy Kerr case '?': 868d831f960SJeremy Kerr usage(argv[0]); 869d66195c1SJeremy Kerr return EXIT_SUCCESS; 870d831f960SJeremy Kerr } 871d831f960SJeremy Kerr } 872d831f960SJeremy Kerr 873*2834c5b1SAndrew Jeffery if (optind < argc) { 8746221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 875*2834c5b1SAndrew Jeffery } 8766221ce94SVishwanatha Subbanna 877d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 878d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 879a72711afSAndrew Jeffery console->pollfds = 880a72711afSAndrew Jeffery calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds)); 881f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 882329a35f5SJeremy Kerr 883d66195c1SJeremy Kerr config = config_init(config_filename); 884d66195c1SJeremy Kerr if (!config) { 885d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 886d66195c1SJeremy Kerr goto out_free; 887d831f960SJeremy Kerr } 888d831f960SJeremy Kerr 889*2834c5b1SAndrew Jeffery if (!config_tty_kname) { 89091dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 891*2834c5b1SAndrew Jeffery } 89291dde14eSAndrew Jeffery 89391dde14eSAndrew Jeffery if (!config_tty_kname) { 89491dde14eSAndrew Jeffery warnx("No TTY device specified"); 89591dde14eSAndrew Jeffery usage(argv[0]); 89691dde14eSAndrew Jeffery return EXIT_FAILURE; 89791dde14eSAndrew Jeffery } 89891dde14eSAndrew Jeffery 8996221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 9006221ce94SVishwanatha Subbanna 901d66195c1SJeremy Kerr rc = tty_init(console, config); 902*2834c5b1SAndrew Jeffery if (rc) { 903d66195c1SJeremy Kerr goto out_config_fini; 904*2834c5b1SAndrew Jeffery } 905d831f960SJeremy Kerr 906f9c8f6caSCheng C Yang dbus_init(console, config); 907f9c8f6caSCheng C Yang 908d47963e5SJeremy Kerr handlers_init(console, config); 909d831f960SJeremy Kerr 9101a0e03b4SJeremy Kerr rc = run_console(console); 911d831f960SJeremy Kerr 9121a0e03b4SJeremy Kerr handlers_fini(console); 913d831f960SJeremy Kerr 914d66195c1SJeremy Kerr out_config_fini: 915d66195c1SJeremy Kerr config_fini(config); 916d66195c1SJeremy Kerr 917957818b4SJeremy Kerr out_free: 91889ea8198SJeremy Kerr free(console->pollers); 91989ea8198SJeremy Kerr free(console->pollfds); 9201a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 9211a0e03b4SJeremy Kerr free(console->tty_dev); 9221a0e03b4SJeremy Kerr free(console); 923d831f960SJeremy Kerr 924d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 925d831f960SJeremy Kerr } 926