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); 11917217845SJeremy Kerr if (rc < 0) 12017217845SJeremy Kerr return -1; 12117217845SJeremy Kerr 12245ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 12345ad7676SYi Li if (!tty_path_input_real) { 12445ad7676SYi Li warn("Can't find realpath for /dev/%s", console->tty_kname); 12515792aa7SAndrew Jeffery rc = -1; 12645ad7676SYi Li goto out_free; 12745ad7676SYi Li } 12845ad7676SYi Li 12945ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 13045ad7676SYi Li if (!tty_kname_real) { 13145ad7676SYi Li warn("Can't find real name for /dev/%s", console->tty_kname); 13215792aa7SAndrew Jeffery rc = -1; 13345ad7676SYi Li goto out_free; 13445ad7676SYi Li } 13545ad7676SYi Li 136a72711afSAndrew Jeffery rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s", 137a72711afSAndrew Jeffery tty_kname_real); 13845ad7676SYi Li if (rc < 0) 13945ad7676SYi Li goto out_free; 14045ad7676SYi Li 14117217845SJeremy Kerr tty_device_tty_dir = realpath(tty_class_device_link, NULL); 14245ad7676SYi Li if (!tty_device_tty_dir) { 14345ad7676SYi Li warn("Can't query sysfs for device %s", tty_kname_real); 14415792aa7SAndrew Jeffery rc = -1; 14517217845SJeremy Kerr goto out_free; 14617217845SJeremy Kerr } 14717217845SJeremy Kerr 14817217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 14917217845SJeremy Kerr if (rc < 0) 15017217845SJeremy Kerr goto out_free; 15117217845SJeremy Kerr 1521a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1531a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 15445ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 15517217845SJeremy Kerr 15645ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 15717217845SJeremy Kerr if (rc < 0) 15817217845SJeremy Kerr goto out_free; 15917217845SJeremy Kerr 16017217845SJeremy Kerr rc = 0; 16117217845SJeremy Kerr 16217217845SJeremy Kerr out_free: 16317217845SJeremy Kerr free(tty_class_device_link); 16417217845SJeremy Kerr free(tty_device_tty_dir); 16517217845SJeremy Kerr free(tty_device_reldir); 16645ad7676SYi Li free(tty_path_input); 16745ad7676SYi Li free(tty_path_input_real); 16817217845SJeremy Kerr return rc; 16917217845SJeremy Kerr } 17017217845SJeremy Kerr 1711a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 172957818b4SJeremy Kerr int value) 173957818b4SJeremy Kerr { 174957818b4SJeremy Kerr char *path; 175957818b4SJeremy Kerr FILE *fp; 176957818b4SJeremy Kerr int rc; 177957818b4SJeremy Kerr 1781a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 179957818b4SJeremy Kerr if (rc < 0) 180957818b4SJeremy Kerr return -1; 181957818b4SJeremy Kerr 182957818b4SJeremy Kerr fp = fopen(path, "w"); 183957818b4SJeremy Kerr if (!fp) { 184a72711afSAndrew Jeffery warn("Can't access attribute %s on device %s", name, 185a72711afSAndrew Jeffery console->tty_kname); 186957818b4SJeremy Kerr rc = -1; 187957818b4SJeremy Kerr goto out_free; 188957818b4SJeremy Kerr } 189957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 190957818b4SJeremy Kerr 191957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 192957818b4SJeremy Kerr if (rc < 0) 193a72711afSAndrew Jeffery warn("Error writing to %s attribute of device %s", name, 194a72711afSAndrew Jeffery console->tty_kname); 195957818b4SJeremy Kerr fclose(fp); 196957818b4SJeremy Kerr 197957818b4SJeremy Kerr out_free: 198957818b4SJeremy Kerr free(path); 199957818b4SJeremy Kerr return rc; 200957818b4SJeremy Kerr } 201957818b4SJeremy Kerr 202d831f960SJeremy Kerr /** 203c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 20454e9569dSJeremy Kerr */ 20554e9569dSJeremy Kerr static void tty_init_termios(struct console *console) 20654e9569dSJeremy Kerr { 20754e9569dSJeremy Kerr struct termios termios; 20854e9569dSJeremy Kerr int rc; 20954e9569dSJeremy Kerr 21054e9569dSJeremy Kerr rc = tcgetattr(console->tty_fd, &termios); 21154e9569dSJeremy Kerr if (rc) { 21254e9569dSJeremy Kerr warn("Can't read tty termios"); 21354e9569dSJeremy Kerr return; 21454e9569dSJeremy Kerr } 21554e9569dSJeremy Kerr 216c7fbcd48SBenjamin Fair if (console->tty_baud) { 217c7fbcd48SBenjamin Fair if (cfsetspeed(&termios, console->tty_baud) < 0) 218c7fbcd48SBenjamin Fair warn("Couldn't set speeds for %s", console->tty_kname); 219c7fbcd48SBenjamin Fair } 220c7fbcd48SBenjamin Fair 221c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 222c7fbcd48SBenjamin Fair * the underlying terminal input/output. 223c7fbcd48SBenjamin Fair */ 22454e9569dSJeremy Kerr cfmakeraw(&termios); 225c7fbcd48SBenjamin Fair 22654e9569dSJeremy Kerr rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 22754e9569dSJeremy Kerr if (rc) 228c7fbcd48SBenjamin Fair warn("Can't set terminal options for %s", console->tty_kname); 22954e9569dSJeremy Kerr } 23054e9569dSJeremy Kerr 231f9c8f6caSCheng C Yang static void tty_change_baudrate(struct console *console) 232f9c8f6caSCheng C Yang { 233f9c8f6caSCheng C Yang struct handler *handler; 234f9c8f6caSCheng C Yang int i, rc; 235f9c8f6caSCheng C Yang 236f9c8f6caSCheng C Yang tty_init_termios(console); 237f9c8f6caSCheng C Yang 238f9c8f6caSCheng C Yang for (i = 0; i < console->n_handlers; i++) { 239f9c8f6caSCheng C Yang handler = console->handlers[i]; 240f9c8f6caSCheng C Yang if (!handler->baudrate) 241f9c8f6caSCheng C Yang continue; 242f9c8f6caSCheng C Yang 243f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 244f9c8f6caSCheng C Yang if (rc) 245f9c8f6caSCheng C Yang warnx("Can't set terminal baudrate for handler %s", 246f9c8f6caSCheng C Yang handler->name); 247f9c8f6caSCheng C Yang } 248f9c8f6caSCheng C Yang } 249f9c8f6caSCheng C Yang 25054e9569dSJeremy Kerr /** 251d831f960SJeremy Kerr * Open and initialise the serial device 252d831f960SJeremy Kerr */ 2531a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 254d831f960SJeremy Kerr { 2551a0e03b4SJeremy Kerr if (console->tty_sirq) 2561a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2571a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 2581a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2591a0e03b4SJeremy Kerr console->tty_lpc_addr); 260957818b4SJeremy Kerr 2611a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2621a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2631a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 264d831f960SJeremy Kerr return -1; 265d831f960SJeremy Kerr } 266d831f960SJeremy Kerr 267d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 268d831f960SJeremy Kerr * we detect larger amounts of data 269d831f960SJeremy Kerr */ 2701a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 271d831f960SJeremy Kerr 27254e9569dSJeremy Kerr tty_init_termios(console); 27354e9569dSJeremy Kerr 274329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 275329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 276329a35f5SJeremy Kerr 277d831f960SJeremy Kerr return 0; 278d831f960SJeremy Kerr } 279d831f960SJeremy Kerr 280d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 281d66195c1SJeremy Kerr { 282fd883a88SAndrew Jeffery unsigned long parsed; 283d66195c1SJeremy Kerr const char *val; 284d66195c1SJeremy Kerr char *endp; 285d66195c1SJeremy Kerr int rc; 286d66195c1SJeremy Kerr 287d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 288d66195c1SJeremy Kerr if (val) { 289fd883a88SAndrew Jeffery errno = 0; 290fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 291fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 292fd883a88SAndrew Jeffery warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'", 293fd883a88SAndrew Jeffery val); 294fd883a88SAndrew Jeffery return -1; 295fd883a88SAndrew Jeffery } 296fd883a88SAndrew Jeffery 297fd883a88SAndrew Jeffery if (parsed > UINT16_MAX) { 298fd883a88SAndrew Jeffery warn("Invalid LPC address '%s'", val); 299fd883a88SAndrew Jeffery return -1; 300fd883a88SAndrew Jeffery } 301fd883a88SAndrew Jeffery 302fd883a88SAndrew Jeffery console->tty_lpc_addr = (uint16_t)parsed; 303d66195c1SJeremy Kerr if (endp == optarg) { 304d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 305d66195c1SJeremy Kerr return -1; 306d66195c1SJeremy Kerr } 307d66195c1SJeremy Kerr } 308d66195c1SJeremy Kerr 309d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 310d66195c1SJeremy Kerr if (val) { 311fd883a88SAndrew Jeffery errno = 0; 312fd883a88SAndrew Jeffery parsed = strtoul(val, &endp, 0); 313fd883a88SAndrew Jeffery if (parsed == ULONG_MAX && errno == ERANGE) { 314fd883a88SAndrew Jeffery warn("Cannot interpret 'sirq' value as an unsigned long: '%s'", 315fd883a88SAndrew Jeffery val); 316fd883a88SAndrew Jeffery } 317fd883a88SAndrew Jeffery 318fd883a88SAndrew Jeffery if (parsed > 16) 319fd883a88SAndrew Jeffery warn("Invalid LPC SERIRQ: '%s'", val); 320fd883a88SAndrew Jeffery 321fd883a88SAndrew Jeffery console->tty_sirq = (int)parsed; 322d66195c1SJeremy Kerr if (endp == optarg) 323d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 324d66195c1SJeremy Kerr } 325d66195c1SJeremy Kerr 326c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 327c7fbcd48SBenjamin Fair if (val) { 328c7fbcd48SBenjamin Fair if (config_parse_baud(&console->tty_baud, val)) 329c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 330c7fbcd48SBenjamin Fair } 331c7fbcd48SBenjamin Fair 332d66195c1SJeremy Kerr if (!console->tty_kname) { 333d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 334d66195c1SJeremy Kerr return -1; 335d66195c1SJeremy Kerr } 336d66195c1SJeremy Kerr 337d66195c1SJeremy Kerr rc = tty_find_device(console); 338d66195c1SJeremy Kerr if (rc) 339d66195c1SJeremy Kerr return rc; 340d66195c1SJeremy Kerr 341d66195c1SJeremy Kerr rc = tty_init_io(console); 342d66195c1SJeremy Kerr return rc; 343d66195c1SJeremy Kerr } 344d66195c1SJeremy Kerr 3451a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 346d831f960SJeremy Kerr { 3471a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 348d831f960SJeremy Kerr } 349d831f960SJeremy Kerr 350f9c8f6caSCheng C Yang static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 351f9c8f6caSCheng C Yang sd_bus_error *err) 352f9c8f6caSCheng C Yang { 353f9c8f6caSCheng C Yang struct console *console = userdata; 354f9c8f6caSCheng C Yang uint32_t baudrate; 355f9c8f6caSCheng C Yang speed_t speed; 356f9c8f6caSCheng C Yang int r; 357f9c8f6caSCheng C Yang 358f9c8f6caSCheng C Yang if (!console) { 359f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 360f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", 0); 361f9c8f6caSCheng C Yang } 362f9c8f6caSCheng C Yang 363f9c8f6caSCheng C Yang r = sd_bus_message_read(msg, "u", &baudrate); 364f9c8f6caSCheng C Yang if (r < 0) { 365f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 366f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 367f9c8f6caSCheng C Yang } 368f9c8f6caSCheng C Yang 369f9c8f6caSCheng C Yang speed = parse_int_to_baud(baudrate); 370f9c8f6caSCheng C Yang if (!speed) { 371f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%u'", baudrate); 372f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 373f9c8f6caSCheng C Yang } 374f9c8f6caSCheng C Yang 375f9c8f6caSCheng C Yang console->tty_baud = speed; 376f9c8f6caSCheng C Yang tty_change_baudrate(console); 377f9c8f6caSCheng C Yang 378f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", r); 379f9c8f6caSCheng C Yang } 380f9c8f6caSCheng C Yang 381fd048328SAndrew Jeffery static int get_handler(sd_bus *bus __attribute__((unused)), 382fd048328SAndrew Jeffery const char *path __attribute__((unused)), 383fd048328SAndrew Jeffery const char *interface __attribute__((unused)), 384fd048328SAndrew Jeffery const char *property __attribute__((unused)), 385fd048328SAndrew Jeffery sd_bus_message *reply, void *userdata, 386a72711afSAndrew Jeffery sd_bus_error *error __attribute__((unused))) 387a72711afSAndrew Jeffery { 388f9c8f6caSCheng C Yang struct console *console = userdata; 389f9c8f6caSCheng C Yang uint32_t baudrate; 390f9c8f6caSCheng C Yang int r; 391f9c8f6caSCheng C Yang 392f9c8f6caSCheng C Yang baudrate = parse_baud_to_int(console->tty_baud); 393f9c8f6caSCheng C Yang if (!baudrate) 394f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 395f9c8f6caSCheng C Yang 396f9c8f6caSCheng C Yang r = sd_bus_message_append(reply, "u", baudrate); 397f9c8f6caSCheng C Yang 398f9c8f6caSCheng C Yang return r; 399f9c8f6caSCheng C Yang } 400f9c8f6caSCheng C Yang 401f9c8f6caSCheng C Yang static const sd_bus_vtable console_vtable[] = { 402f9c8f6caSCheng C Yang SD_BUS_VTABLE_START(0), 403f9c8f6caSCheng C Yang SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 404f9c8f6caSCheng C Yang SD_BUS_VTABLE_UNPRIVILEGED), 405f9c8f6caSCheng C Yang SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 406a72711afSAndrew Jeffery SD_BUS_VTABLE_END, 407a72711afSAndrew Jeffery }; 408f9c8f6caSCheng C Yang 409a72711afSAndrew Jeffery static void dbus_init(struct console *console, 410a72711afSAndrew Jeffery struct config *config __attribute__((unused))) 411f9c8f6caSCheng C Yang { 412f9c8f6caSCheng C Yang int dbus_poller = 0; 413f9c8f6caSCheng C Yang int fd, r; 414f9c8f6caSCheng C Yang 415f9c8f6caSCheng C Yang if (!console) { 416f9c8f6caSCheng C Yang warnx("Couldn't get valid console"); 417f9c8f6caSCheng C Yang return; 418f9c8f6caSCheng C Yang } 419f9c8f6caSCheng C Yang 420f9c8f6caSCheng C Yang r = sd_bus_default_system(&console->bus); 421f9c8f6caSCheng C Yang if (r < 0) { 422f9c8f6caSCheng C Yang warnx("Failed to connect to system bus: %s", strerror(-r)); 423f9c8f6caSCheng C Yang return; 424f9c8f6caSCheng C Yang } 425f9c8f6caSCheng C Yang 426f9c8f6caSCheng C Yang r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 427f9c8f6caSCheng C Yang console_vtable, console); 428f9c8f6caSCheng C Yang if (r < 0) { 429f9c8f6caSCheng C Yang warnx("Failed to issue method call: %s", strerror(-r)); 430f9c8f6caSCheng C Yang return; 431f9c8f6caSCheng C Yang } 432f9c8f6caSCheng C Yang 433a72711afSAndrew Jeffery r = sd_bus_request_name(console->bus, DBUS_NAME, 434a72711afSAndrew Jeffery SD_BUS_NAME_ALLOW_REPLACEMENT | 435a72711afSAndrew Jeffery SD_BUS_NAME_REPLACE_EXISTING); 436f9c8f6caSCheng C Yang if (r < 0) { 437f9c8f6caSCheng C Yang warnx("Failed to acquire service name: %s", strerror(-r)); 438f9c8f6caSCheng C Yang return; 439f9c8f6caSCheng C Yang } 440f9c8f6caSCheng C Yang 441f9c8f6caSCheng C Yang fd = sd_bus_get_fd(console->bus); 442f9c8f6caSCheng C Yang if (fd < 0) { 443f9c8f6caSCheng C Yang warnx("Couldn't get the bus file descriptor"); 444f9c8f6caSCheng C Yang return; 445f9c8f6caSCheng C Yang } 446f9c8f6caSCheng C Yang 447f9c8f6caSCheng C Yang dbus_poller = POLLFD_DBUS; 448f9c8f6caSCheng C Yang 449f9c8f6caSCheng C Yang console->pollfds[dbus_poller].fd = fd; 450f9c8f6caSCheng C Yang console->pollfds[dbus_poller].events = POLLIN; 451f9c8f6caSCheng C Yang } 452f9c8f6caSCheng C Yang 453d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 454d831f960SJeremy Kerr { 455750fb0c0SAndrew Jeffery /* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */ 4561a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 4571a0e03b4SJeremy Kerr struct handler *handler; 458021b91f0SJeremy Kerr int i, rc; 459d831f960SJeremy Kerr 4601a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4611a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 462d831f960SJeremy Kerr 4635c359cc6SAndrew Jeffery printf("%ld handler%s\n", console->n_handlers, 4641a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 465d831f960SJeremy Kerr 4661a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4671a0e03b4SJeremy Kerr handler = console->handlers[i]; 4681a0e03b4SJeremy Kerr 469021b91f0SJeremy Kerr rc = 0; 4701a0e03b4SJeremy Kerr if (handler->init) 471021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 472021b91f0SJeremy Kerr 473021b91f0SJeremy Kerr handler->active = rc == 0; 474021b91f0SJeremy Kerr 475021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 476021b91f0SJeremy Kerr handler->active ? "" : "in"); 477d831f960SJeremy Kerr } 478d831f960SJeremy Kerr } 479d831f960SJeremy Kerr 4801a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 481d831f960SJeremy Kerr { 4821a0e03b4SJeremy Kerr struct handler *handler; 4831a0e03b4SJeremy Kerr int i; 4841a0e03b4SJeremy Kerr 4851a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4861a0e03b4SJeremy Kerr handler = console->handlers[i]; 487021b91f0SJeremy Kerr if (handler->fini && handler->active) 4881a0e03b4SJeremy Kerr handler->fini(handler); 4891a0e03b4SJeremy Kerr } 490d831f960SJeremy Kerr } 491d831f960SJeremy Kerr 4921cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 4931cecc5deSJohnathan Mantey { 4941cecc5deSJohnathan Mantey struct timespec t; 4951cecc5deSJohnathan Mantey int rc; 4961cecc5deSJohnathan Mantey 4971cecc5deSJohnathan Mantey /* 4981cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 4991cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 5001cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 5011cecc5deSJohnathan Mantey */ 5021cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 5031cecc5deSJohnathan Mantey if (rc) 5041cecc5deSJohnathan Mantey return rc; 5051cecc5deSJohnathan Mantey 5061cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 5071cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 5081cecc5deSJohnathan Mantey 5091cecc5deSJohnathan Mantey return 0; 5101cecc5deSJohnathan Mantey } 5111cecc5deSJohnathan Mantey 512a72711afSAndrew Jeffery struct ringbuffer_consumer * 513a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console, 514f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 515d831f960SJeremy Kerr { 516f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 517d831f960SJeremy Kerr } 518d831f960SJeremy Kerr 51955c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 520a72711afSAndrew Jeffery struct handler *handler, 521a72711afSAndrew Jeffery poller_event_fn_t poller_fn, 5221cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 5231cecc5deSJohnathan Mantey int events, void *data) 524d831f960SJeremy Kerr { 525329a35f5SJeremy Kerr struct poller *poller; 5265c359cc6SAndrew Jeffery long n; 527329a35f5SJeremy Kerr 528329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 529329a35f5SJeremy Kerr poller->remove = false; 530329a35f5SJeremy Kerr poller->handler = handler; 5311cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5321cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 533329a35f5SJeremy Kerr poller->data = data; 534329a35f5SJeremy Kerr 535329a35f5SJeremy Kerr /* add one to our pollers array */ 536329a35f5SJeremy Kerr n = console->n_pollers++; 537*91b52175SAndrew Jeffery /* 538*91b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 539*91b52175SAndrew Jeffery * pointer type. 540*91b52175SAndrew Jeffery */ 541*91b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 542*91b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 543*91b52175SAndrew Jeffery sizeof(*console->pollers)); 544*91b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 545329a35f5SJeremy Kerr 546329a35f5SJeremy Kerr console->pollers[n] = poller; 547329a35f5SJeremy Kerr 548329a35f5SJeremy Kerr /* increase pollfds array too */ 549a72711afSAndrew Jeffery console->pollfds = 550*91b52175SAndrew Jeffery reallocarray(console->pollfds, 551*91b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 552*91b52175SAndrew Jeffery sizeof(*console->pollfds)); 553329a35f5SJeremy Kerr 554329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 555a72711afSAndrew Jeffery memcpy(&console->pollfds[n + 1], &console->pollfds[n], 556f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 557329a35f5SJeremy Kerr 558329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 5595c359cc6SAndrew Jeffery console->pollfds[n].events = (short)(events & 0x7fff); 560329a35f5SJeremy Kerr 561329a35f5SJeremy Kerr return poller; 562329a35f5SJeremy Kerr } 563329a35f5SJeremy Kerr 564a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller) 565329a35f5SJeremy Kerr { 566329a35f5SJeremy Kerr int i; 567329a35f5SJeremy Kerr 568329a35f5SJeremy Kerr /* find the entry in our pollers array */ 569329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 570329a35f5SJeremy Kerr if (console->pollers[i] == poller) 571329a35f5SJeremy Kerr break; 572329a35f5SJeremy Kerr 573329a35f5SJeremy Kerr assert(i < console->n_pollers); 574329a35f5SJeremy Kerr 575329a35f5SJeremy Kerr console->n_pollers--; 576329a35f5SJeremy Kerr 577*91b52175SAndrew Jeffery /* 578*91b52175SAndrew Jeffery * Remove the item from the pollers array... 579*91b52175SAndrew Jeffery * 580*91b52175SAndrew Jeffery * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a 581*91b52175SAndrew Jeffery * pointer type. 582*91b52175SAndrew Jeffery */ 583*91b52175SAndrew Jeffery /* NOLINTBEGIN(bugprone-sizeof-expression) */ 584329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i + 1], 585a72711afSAndrew Jeffery sizeof(*console->pollers) * (console->n_pollers - i)); 586329a35f5SJeremy Kerr 587*91b52175SAndrew Jeffery console->pollers = reallocarray(console->pollers, console->n_pollers, 588*91b52175SAndrew Jeffery sizeof(*console->pollers)); 589*91b52175SAndrew Jeffery /* NOLINTEND(bugprone-sizeof-expression) */ 590329a35f5SJeremy Kerr 591329a35f5SJeremy Kerr /* ... and the pollfds array */ 592329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i + 1], 593329a35f5SJeremy Kerr sizeof(*console->pollfds) * 594f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 595329a35f5SJeremy Kerr 596a72711afSAndrew Jeffery console->pollfds = 597*91b52175SAndrew Jeffery reallocarray(console->pollfds, 598*91b52175SAndrew Jeffery (MAX_INTERNAL_POLLFD + console->n_pollers), 599*91b52175SAndrew Jeffery sizeof(*console->pollfds)); 600329a35f5SJeremy Kerr 601329a35f5SJeremy Kerr free(poller); 602329a35f5SJeremy Kerr } 603329a35f5SJeremy Kerr 6046b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 6056b1fed27SJeremy Kerr int events) 6066b1fed27SJeremy Kerr { 6076b1fed27SJeremy Kerr int i; 6086b1fed27SJeremy Kerr 6096b1fed27SJeremy Kerr /* find the entry in our pollers array */ 6106b1fed27SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 6116b1fed27SJeremy Kerr if (console->pollers[i] == poller) 6126b1fed27SJeremy Kerr break; 6136b1fed27SJeremy Kerr 6145c359cc6SAndrew Jeffery console->pollfds[i].events = (short)(events & 0x7fff); 6156b1fed27SJeremy Kerr } 6166b1fed27SJeremy Kerr 617fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 618fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 6191cecc5deSJohnathan Mantey { 6201cecc5deSJohnathan Mantey struct timeval now; 6211cecc5deSJohnathan Mantey int rc; 6221cecc5deSJohnathan Mantey 6231cecc5deSJohnathan Mantey rc = get_current_time(&now); 6241cecc5deSJohnathan Mantey if (rc) 6251cecc5deSJohnathan Mantey return; 6261cecc5deSJohnathan Mantey 6271cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 6281cecc5deSJohnathan Mantey } 6291cecc5deSJohnathan Mantey 6305c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time) 6311cecc5deSJohnathan Mantey { 6321cecc5deSJohnathan Mantey struct timeval *earliest, interval; 6331cecc5deSJohnathan Mantey struct poller *poller; 6341cecc5deSJohnathan Mantey int i; 6351cecc5deSJohnathan Mantey 6361cecc5deSJohnathan Mantey earliest = NULL; 6371cecc5deSJohnathan Mantey 6381cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 6391cecc5deSJohnathan Mantey poller = console->pollers[i]; 6401cecc5deSJohnathan Mantey 6411cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6421cecc5deSJohnathan Mantey (!earliest || 6431cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))) { 6441cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6451cecc5deSJohnathan Mantey // function to timeout. 6461cecc5deSJohnathan Mantey earliest = &poller->timeout; 6471cecc5deSJohnathan Mantey } 6481cecc5deSJohnathan Mantey } 6491cecc5deSJohnathan Mantey 6501cecc5deSJohnathan Mantey if (earliest) { 6511cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6521cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6531cecc5deSJohnathan Mantey * not elapsed */ 6541cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6551cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6561cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 6571cecc5deSJohnathan Mantey } else { 6581cecc5deSJohnathan Mantey /* return from poll immediately */ 6591cecc5deSJohnathan Mantey return 0; 6601cecc5deSJohnathan Mantey } 6611cecc5deSJohnathan Mantey } else { 6621cecc5deSJohnathan Mantey /* poll indefinitely */ 6631cecc5deSJohnathan Mantey return -1; 6641cecc5deSJohnathan Mantey } 6651cecc5deSJohnathan Mantey } 6661cecc5deSJohnathan Mantey 6671cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 668329a35f5SJeremy Kerr { 669329a35f5SJeremy Kerr struct poller *poller; 670329a35f5SJeremy Kerr struct pollfd *pollfd; 671329a35f5SJeremy Kerr enum poller_ret prc; 672329a35f5SJeremy Kerr int i, rc; 673d831f960SJeremy Kerr 6741a0e03b4SJeremy Kerr rc = 0; 6751a0e03b4SJeremy Kerr 676329a35f5SJeremy Kerr /* 677329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 678329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 679329a35f5SJeremy Kerr */ 680329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 681329a35f5SJeremy Kerr poller = console->pollers[i]; 682329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 6831cecc5deSJohnathan Mantey prc = POLLER_OK; 6841a0e03b4SJeremy Kerr 6851cecc5deSJohnathan Mantey /* process pending events... */ 6861cecc5deSJohnathan Mantey if (pollfd->revents) { 6871cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 688329a35f5SJeremy Kerr poller->data); 689329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 690329a35f5SJeremy Kerr rc = -1; 691329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 692329a35f5SJeremy Kerr poller->remove = true; 693329a35f5SJeremy Kerr } 694329a35f5SJeremy Kerr 6951cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 6961cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 6971cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 6981cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 6991cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 7001cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 7011cecc5deSJohnathan Mantey transmission. */ 7021cecc5deSJohnathan Mantey timerclear(&poller->timeout); 7031cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 7041cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 7051cecc5deSJohnathan Mantey rc = -1; 7061cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 7071cecc5deSJohnathan Mantey poller->remove = true; 7081cecc5deSJohnathan Mantey } 7091cecc5deSJohnathan Mantey } 7101cecc5deSJohnathan Mantey } 7111cecc5deSJohnathan Mantey 712329a35f5SJeremy Kerr /** 713329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 714329a35f5SJeremy Kerr * the array will have changed 715329a35f5SJeremy Kerr */ 716329a35f5SJeremy Kerr for (;;) { 717329a35f5SJeremy Kerr bool removed = false; 718329a35f5SJeremy Kerr 719329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 720329a35f5SJeremy Kerr poller = console->pollers[i]; 721329a35f5SJeremy Kerr if (poller->remove) { 72255c9712dSJeremy Kerr console_poller_unregister(console, poller); 723329a35f5SJeremy Kerr removed = true; 724329a35f5SJeremy Kerr break; 725329a35f5SJeremy Kerr } 726329a35f5SJeremy Kerr } 727329a35f5SJeremy Kerr if (!removed) 728329a35f5SJeremy Kerr break; 7291a0e03b4SJeremy Kerr } 7301a0e03b4SJeremy Kerr 7311a0e03b4SJeremy Kerr return rc; 7321a0e03b4SJeremy Kerr } 7331a0e03b4SJeremy Kerr 734769cee1aSJeremy Kerr static void sighandler(int signal) 735769cee1aSJeremy Kerr { 736769cee1aSJeremy Kerr if (signal == SIGINT) 737769cee1aSJeremy Kerr sigint = true; 738769cee1aSJeremy Kerr } 739769cee1aSJeremy Kerr 7401a0e03b4SJeremy Kerr int run_console(struct console *console) 7411a0e03b4SJeremy Kerr { 7425c359cc6SAndrew Jeffery sighandler_t sighandler_save = signal(SIGINT, sighandler); 7431cecc5deSJohnathan Mantey struct timeval tv; 7445c359cc6SAndrew Jeffery long timeout; 7455c359cc6SAndrew Jeffery ssize_t rc; 746769cee1aSJeremy Kerr 747769cee1aSJeremy Kerr rc = 0; 748769cee1aSJeremy Kerr 749d831f960SJeremy Kerr for (;;) { 750d831f960SJeremy Kerr uint8_t buf[4096]; 751d831f960SJeremy Kerr 7521764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7531764145dSJeremy Kerr 754769cee1aSJeremy Kerr if (sigint) { 755769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 756769cee1aSJeremy Kerr break; 757769cee1aSJeremy Kerr } 758769cee1aSJeremy Kerr 7591cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7601cecc5deSJohnathan Mantey if (rc) { 7611cecc5deSJohnathan Mantey warn("Failed to read current time"); 7621cecc5deSJohnathan Mantey break; 7631cecc5deSJohnathan Mantey } 7641cecc5deSJohnathan Mantey 7651cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7661cecc5deSJohnathan Mantey 767329a35f5SJeremy Kerr rc = poll(console->pollfds, 7685c359cc6SAndrew Jeffery console->n_pollers + MAX_INTERNAL_POLLFD, 7695c359cc6SAndrew Jeffery (int)timeout); 7701cecc5deSJohnathan Mantey 771d831f960SJeremy Kerr if (rc < 0) { 772769cee1aSJeremy Kerr if (errno == EINTR) { 773769cee1aSJeremy Kerr continue; 774769cee1aSJeremy Kerr } else { 775d831f960SJeremy Kerr warn("poll error"); 776769cee1aSJeremy Kerr break; 777769cee1aSJeremy Kerr } 778d831f960SJeremy Kerr } 779d831f960SJeremy Kerr 780329a35f5SJeremy Kerr /* process internal fd first */ 781329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 7821a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 783d831f960SJeremy Kerr if (rc <= 0) { 784d831f960SJeremy Kerr warn("Error reading from tty device"); 785769cee1aSJeremy Kerr rc = -1; 786769cee1aSJeremy Kerr break; 787d831f960SJeremy Kerr } 788f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 7891a0e03b4SJeremy Kerr if (rc) 790769cee1aSJeremy Kerr break; 791d831f960SJeremy Kerr } 792d831f960SJeremy Kerr 793f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 794f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 795f9c8f6caSCheng C Yang } 796f9c8f6caSCheng C Yang 797329a35f5SJeremy Kerr /* ... and then the pollers */ 7981cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 7991a0e03b4SJeremy Kerr if (rc) 800769cee1aSJeremy Kerr break; 8011a0e03b4SJeremy Kerr } 802769cee1aSJeremy Kerr 803769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 804f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 805769cee1aSJeremy Kerr 806769cee1aSJeremy Kerr return rc ? -1 : 0; 8071a0e03b4SJeremy Kerr } 808d831f960SJeremy Kerr static const struct option options[] = { 809d66195c1SJeremy Kerr { "config", required_argument, 0, 'c' }, 810f5858b5bSJoel Stanley { 0, 0, 0, 0 }, 811d831f960SJeremy Kerr }; 812d831f960SJeremy Kerr 813d831f960SJeremy Kerr int main(int argc, char **argv) 814d831f960SJeremy Kerr { 815d66195c1SJeremy Kerr const char *config_filename = NULL; 8166221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 8171a0e03b4SJeremy Kerr struct console *console; 818d66195c1SJeremy Kerr struct config *config; 819d66195c1SJeremy Kerr int rc; 820d831f960SJeremy Kerr 821957818b4SJeremy Kerr rc = -1; 822d831f960SJeremy Kerr 823d831f960SJeremy Kerr for (;;) { 824d831f960SJeremy Kerr int c, idx; 825d831f960SJeremy Kerr 826d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 827d831f960SJeremy Kerr if (c == -1) 828d831f960SJeremy Kerr break; 829d831f960SJeremy Kerr 830d831f960SJeremy Kerr switch (c) { 831d66195c1SJeremy Kerr case 'c': 832d66195c1SJeremy Kerr config_filename = optarg; 833d831f960SJeremy Kerr break; 834d831f960SJeremy Kerr case 'h': 835d831f960SJeremy Kerr case '?': 836d831f960SJeremy Kerr usage(argv[0]); 837d66195c1SJeremy Kerr return EXIT_SUCCESS; 838d831f960SJeremy Kerr } 839d831f960SJeremy Kerr } 840d831f960SJeremy Kerr 84191dde14eSAndrew Jeffery if (optind < argc) 8426221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8436221ce94SVishwanatha Subbanna 844d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 845d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 846a72711afSAndrew Jeffery console->pollfds = 847a72711afSAndrew Jeffery calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds)); 848f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 849329a35f5SJeremy Kerr 850d66195c1SJeremy Kerr config = config_init(config_filename); 851d66195c1SJeremy Kerr if (!config) { 852d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 853d66195c1SJeremy Kerr goto out_free; 854d831f960SJeremy Kerr } 855d831f960SJeremy Kerr 85691dde14eSAndrew Jeffery if (!config_tty_kname) 85791dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 85891dde14eSAndrew Jeffery 85991dde14eSAndrew Jeffery if (!config_tty_kname) { 86091dde14eSAndrew Jeffery warnx("No TTY device specified"); 86191dde14eSAndrew Jeffery usage(argv[0]); 86291dde14eSAndrew Jeffery return EXIT_FAILURE; 86391dde14eSAndrew Jeffery } 86491dde14eSAndrew Jeffery 8656221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 8666221ce94SVishwanatha Subbanna 867d66195c1SJeremy Kerr rc = tty_init(console, config); 86817217845SJeremy Kerr if (rc) 869d66195c1SJeremy Kerr goto out_config_fini; 870d831f960SJeremy Kerr 871f9c8f6caSCheng C Yang dbus_init(console, config); 872f9c8f6caSCheng C Yang 873d47963e5SJeremy Kerr handlers_init(console, config); 874d831f960SJeremy Kerr 8751a0e03b4SJeremy Kerr rc = run_console(console); 876d831f960SJeremy Kerr 8771a0e03b4SJeremy Kerr handlers_fini(console); 878d831f960SJeremy Kerr 879d66195c1SJeremy Kerr out_config_fini: 880d66195c1SJeremy Kerr config_fini(config); 881d66195c1SJeremy Kerr 882957818b4SJeremy Kerr out_free: 88389ea8198SJeremy Kerr free(console->pollers); 88489ea8198SJeremy Kerr free(console->pollfds); 8851a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 8861a0e03b4SJeremy Kerr free(console->tty_dev); 8871a0e03b4SJeremy Kerr free(console); 888d831f960SJeremy Kerr 889d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 890d831f960SJeremy Kerr } 891