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 1917217845SJeremy Kerr #define _GNU_SOURCE 2017217845SJeremy Kerr 21329a35f5SJeremy Kerr #include <assert.h> 22769cee1aSJeremy Kerr #include <errno.h> 23769cee1aSJeremy Kerr #include <signal.h> 24d831f960SJeremy Kerr #include <stdint.h> 25d831f960SJeremy Kerr #include <stdbool.h> 26d831f960SJeremy Kerr #include <stdlib.h> 27d831f960SJeremy Kerr #include <stdio.h> 28d831f960SJeremy Kerr #include <fcntl.h> 29d831f960SJeremy Kerr #include <unistd.h> 30d831f960SJeremy Kerr #include <err.h> 31d831f960SJeremy Kerr #include <string.h> 32d831f960SJeremy Kerr #include <getopt.h> 3317217845SJeremy Kerr #include <limits.h> 341cecc5deSJohnathan Mantey #include <time.h> 3554e9569dSJeremy Kerr #include <termios.h> 36d831f960SJeremy Kerr 37d831f960SJeremy Kerr #include <sys/types.h> 381cecc5deSJohnathan Mantey #include <sys/time.h> 3987e344cdSJoel Stanley #include <poll.h> 40d831f960SJeremy Kerr 411a0e03b4SJeremy Kerr #include "console-server.h" 42d831f960SJeremy Kerr 43f9c8f6caSCheng C Yang #define DBUS_ERR "org.openbmc.error" 44f9c8f6caSCheng C Yang #define DBUS_NAME "xyz.openbmc_project.console" 45f9c8f6caSCheng C Yang #define OBJ_NAME "/xyz/openbmc_project/console" 46f9c8f6caSCheng C Yang 471a0e03b4SJeremy Kerr struct console { 4817217845SJeremy Kerr const char *tty_kname; 4917217845SJeremy Kerr char *tty_sysfs_devnode; 5017217845SJeremy Kerr char *tty_dev; 51957818b4SJeremy Kerr int tty_sirq; 52957818b4SJeremy Kerr int tty_lpc_addr; 53c7fbcd48SBenjamin Fair speed_t tty_baud; 54d831f960SJeremy Kerr int tty_fd; 55329a35f5SJeremy Kerr 56f733c85aSJeremy Kerr struct ringbuffer *rb; 57f733c85aSJeremy Kerr 581a0e03b4SJeremy Kerr struct handler **handlers; 591a0e03b4SJeremy Kerr int n_handlers; 60329a35f5SJeremy Kerr 61329a35f5SJeremy Kerr struct poller **pollers; 62329a35f5SJeremy Kerr int n_pollers; 63329a35f5SJeremy Kerr 64329a35f5SJeremy Kerr struct pollfd *pollfds; 65f9c8f6caSCheng C Yang struct sd_bus *bus; 66d831f960SJeremy Kerr }; 67d831f960SJeremy Kerr 68329a35f5SJeremy Kerr struct poller { 69329a35f5SJeremy Kerr struct handler *handler; 70329a35f5SJeremy Kerr void *data; 711cecc5deSJohnathan Mantey poller_event_fn_t event_fn; 721cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn; 731cecc5deSJohnathan Mantey struct timeval timeout; 74329a35f5SJeremy Kerr bool remove; 75329a35f5SJeremy Kerr }; 76329a35f5SJeremy Kerr 77f9c8f6caSCheng C Yang /* we have two extra entry in the pollfds array for the VUART tty */ 78f9c8f6caSCheng C Yang enum internal_pollfds { 79f9c8f6caSCheng C Yang POLLFD_HOSTTTY = 0, 80f9c8f6caSCheng C Yang POLLFD_DBUS = 1, 81f9c8f6caSCheng C Yang MAX_INTERNAL_POLLFD = 2, 82f9c8f6caSCheng C Yang }; 83329a35f5SJeremy Kerr 84f733c85aSJeremy Kerr /* size of the shared backlog ringbuffer */ 85f733c85aSJeremy Kerr const size_t buffer_size = 128 * 1024; 86f733c85aSJeremy Kerr 87769cee1aSJeremy Kerr /* state shared with the signal handler */ 88769cee1aSJeremy Kerr static bool sigint; 89329a35f5SJeremy Kerr 90d831f960SJeremy Kerr static void usage(const char *progname) 91d831f960SJeremy Kerr { 92d831f960SJeremy Kerr fprintf(stderr, 936221ce94SVishwanatha Subbanna "usage: %s [options] <DEVICE>\n" 94d831f960SJeremy Kerr "\n" 95d831f960SJeremy Kerr "Options:\n" 96d66195c1SJeremy Kerr " --config <FILE> Use FILE for configuration\n" 97d831f960SJeremy Kerr "", 98d831f960SJeremy Kerr progname); 99d831f960SJeremy Kerr } 100d831f960SJeremy Kerr 10117217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */ 1021a0e03b4SJeremy Kerr static int tty_find_device(struct console *console) 10317217845SJeremy Kerr { 10417217845SJeremy Kerr char *tty_class_device_link; 10517217845SJeremy Kerr char *tty_device_tty_dir; 10617217845SJeremy Kerr char *tty_device_reldir; 10745ad7676SYi Li char *tty_path_input; 10845ad7676SYi Li char *tty_path_input_real; 10945ad7676SYi Li char *tty_kname_real; 11017217845SJeremy Kerr int rc; 11117217845SJeremy Kerr 11217217845SJeremy Kerr tty_class_device_link = NULL; 11317217845SJeremy Kerr tty_device_tty_dir = NULL; 11417217845SJeremy Kerr tty_device_reldir = NULL; 11545ad7676SYi Li tty_path_input = NULL; 11645ad7676SYi Li tty_path_input_real = NULL; 11745ad7676SYi Li tty_kname_real = NULL; 11817217845SJeremy Kerr 11945ad7676SYi Li /* udev may rename the tty name with a symbol link, try to resolve */ 12045ad7676SYi Li rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname); 12117217845SJeremy Kerr if (rc < 0) 12217217845SJeremy Kerr return -1; 12317217845SJeremy Kerr 12445ad7676SYi Li tty_path_input_real = realpath(tty_path_input, NULL); 12545ad7676SYi Li if (!tty_path_input_real) { 12645ad7676SYi Li warn("Can't find realpath for /dev/%s", console->tty_kname); 127*15792aa7SAndrew Jeffery rc = -1; 12845ad7676SYi Li goto out_free; 12945ad7676SYi Li } 13045ad7676SYi Li 13145ad7676SYi Li tty_kname_real = basename(tty_path_input_real); 13245ad7676SYi Li if (!tty_kname_real) { 13345ad7676SYi Li warn("Can't find real name for /dev/%s", console->tty_kname); 134*15792aa7SAndrew Jeffery rc = -1; 13545ad7676SYi Li goto out_free; 13645ad7676SYi Li } 13745ad7676SYi Li 13845ad7676SYi Li rc = asprintf(&tty_class_device_link, 13945ad7676SYi Li "/sys/class/tty/%s", tty_kname_real); 14045ad7676SYi Li if (rc < 0) 14145ad7676SYi Li goto out_free; 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); 146*15792aa7SAndrew Jeffery rc = -1; 14717217845SJeremy Kerr goto out_free; 14817217845SJeremy Kerr } 14917217845SJeremy Kerr 15017217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 15117217845SJeremy Kerr if (rc < 0) 15217217845SJeremy Kerr goto out_free; 15317217845SJeremy Kerr 1541a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1551a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 15645ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 15717217845SJeremy Kerr 15845ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 15917217845SJeremy Kerr if (rc < 0) 16017217845SJeremy Kerr goto out_free; 16117217845SJeremy Kerr 16217217845SJeremy Kerr rc = 0; 16317217845SJeremy Kerr 16417217845SJeremy Kerr out_free: 16517217845SJeremy Kerr free(tty_class_device_link); 16617217845SJeremy Kerr free(tty_device_tty_dir); 16717217845SJeremy Kerr free(tty_device_reldir); 16845ad7676SYi Li free(tty_path_input); 16945ad7676SYi Li free(tty_path_input_real); 17017217845SJeremy Kerr return rc; 17117217845SJeremy Kerr } 17217217845SJeremy Kerr 1731a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 174957818b4SJeremy Kerr int value) 175957818b4SJeremy Kerr { 176957818b4SJeremy Kerr char *path; 177957818b4SJeremy Kerr FILE *fp; 178957818b4SJeremy Kerr int rc; 179957818b4SJeremy Kerr 1801a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 181957818b4SJeremy Kerr if (rc < 0) 182957818b4SJeremy Kerr return -1; 183957818b4SJeremy Kerr 184957818b4SJeremy Kerr fp = fopen(path, "w"); 185957818b4SJeremy Kerr if (!fp) { 186957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1871a0e03b4SJeremy Kerr name, console->tty_kname); 188957818b4SJeremy Kerr rc = -1; 189957818b4SJeremy Kerr goto out_free; 190957818b4SJeremy Kerr } 191957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 192957818b4SJeremy Kerr 193957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 194957818b4SJeremy Kerr if (rc < 0) 195957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1961a0e03b4SJeremy Kerr name, console->tty_kname); 197957818b4SJeremy Kerr fclose(fp); 198957818b4SJeremy Kerr 199957818b4SJeremy Kerr 200957818b4SJeremy Kerr 201957818b4SJeremy Kerr out_free: 202957818b4SJeremy Kerr free(path); 203957818b4SJeremy Kerr return rc; 204957818b4SJeremy Kerr } 205957818b4SJeremy Kerr 206d831f960SJeremy Kerr /** 207c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 20854e9569dSJeremy Kerr */ 20954e9569dSJeremy Kerr static void tty_init_termios(struct console *console) 21054e9569dSJeremy Kerr { 21154e9569dSJeremy Kerr struct termios termios; 21254e9569dSJeremy Kerr int rc; 21354e9569dSJeremy Kerr 21454e9569dSJeremy Kerr rc = tcgetattr(console->tty_fd, &termios); 21554e9569dSJeremy Kerr if (rc) { 21654e9569dSJeremy Kerr warn("Can't read tty termios"); 21754e9569dSJeremy Kerr return; 21854e9569dSJeremy Kerr } 21954e9569dSJeremy Kerr 220c7fbcd48SBenjamin Fair if (console->tty_baud) { 221c7fbcd48SBenjamin Fair if (cfsetspeed(&termios, console->tty_baud) < 0) 222c7fbcd48SBenjamin Fair warn("Couldn't set speeds for %s", console->tty_kname); 223c7fbcd48SBenjamin Fair } 224c7fbcd48SBenjamin Fair 225c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 226c7fbcd48SBenjamin Fair * the underlying terminal input/output. 227c7fbcd48SBenjamin Fair */ 22854e9569dSJeremy Kerr cfmakeraw(&termios); 229c7fbcd48SBenjamin Fair 23054e9569dSJeremy Kerr rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 23154e9569dSJeremy Kerr if (rc) 232c7fbcd48SBenjamin Fair warn("Can't set terminal options for %s", console->tty_kname); 23354e9569dSJeremy Kerr } 23454e9569dSJeremy Kerr 235f9c8f6caSCheng C Yang 236f9c8f6caSCheng C Yang static void tty_change_baudrate(struct console *console) 237f9c8f6caSCheng C Yang { 238f9c8f6caSCheng C Yang struct handler *handler; 239f9c8f6caSCheng C Yang int i, rc; 240f9c8f6caSCheng C Yang 241f9c8f6caSCheng C Yang tty_init_termios(console); 242f9c8f6caSCheng C Yang 243f9c8f6caSCheng C Yang for (i = 0; i < console->n_handlers; i++) { 244f9c8f6caSCheng C Yang handler = console->handlers[i]; 245f9c8f6caSCheng C Yang if (!handler->baudrate) 246f9c8f6caSCheng C Yang continue; 247f9c8f6caSCheng C Yang 248f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 249f9c8f6caSCheng C Yang if (rc) 250f9c8f6caSCheng C Yang warnx("Can't set terminal baudrate for handler %s", 251f9c8f6caSCheng C Yang handler->name); 252f9c8f6caSCheng C Yang } 253f9c8f6caSCheng C Yang } 254f9c8f6caSCheng C Yang 25554e9569dSJeremy Kerr /** 256d831f960SJeremy Kerr * Open and initialise the serial device 257d831f960SJeremy Kerr */ 2581a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 259d831f960SJeremy Kerr { 2601a0e03b4SJeremy Kerr if (console->tty_sirq) 2611a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2621a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 2631a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2641a0e03b4SJeremy Kerr console->tty_lpc_addr); 265957818b4SJeremy Kerr 2661a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2671a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2681a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 269d831f960SJeremy Kerr return -1; 270d831f960SJeremy Kerr } 271d831f960SJeremy Kerr 272d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 273d831f960SJeremy Kerr * we detect larger amounts of data 274d831f960SJeremy Kerr */ 2751a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 276d831f960SJeremy Kerr 27754e9569dSJeremy Kerr tty_init_termios(console); 27854e9569dSJeremy Kerr 279329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 280329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 281329a35f5SJeremy Kerr 282d831f960SJeremy Kerr return 0; 283d831f960SJeremy Kerr } 284d831f960SJeremy Kerr 285d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 286d66195c1SJeremy Kerr { 287d66195c1SJeremy Kerr const char *val; 288d66195c1SJeremy Kerr char *endp; 289d66195c1SJeremy Kerr int rc; 290d66195c1SJeremy Kerr 291d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 292d66195c1SJeremy Kerr if (val) { 293d66195c1SJeremy Kerr console->tty_lpc_addr = strtoul(val, &endp, 0); 294d66195c1SJeremy Kerr if (endp == optarg) { 295d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 296d66195c1SJeremy Kerr return -1; 297d66195c1SJeremy Kerr } 298d66195c1SJeremy Kerr } 299d66195c1SJeremy Kerr 300d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 301d66195c1SJeremy Kerr if (val) { 302d66195c1SJeremy Kerr console->tty_sirq = strtoul(val, &endp, 0); 303d66195c1SJeremy Kerr if (endp == optarg) 304d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 305d66195c1SJeremy Kerr } 306d66195c1SJeremy Kerr 307c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 308c7fbcd48SBenjamin Fair if (val) { 309c7fbcd48SBenjamin Fair if (config_parse_baud(&console->tty_baud, val)) 310c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 311c7fbcd48SBenjamin Fair } 312c7fbcd48SBenjamin Fair 313d66195c1SJeremy Kerr if (!console->tty_kname) { 314d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 315d66195c1SJeremy Kerr return -1; 316d66195c1SJeremy Kerr } 317d66195c1SJeremy Kerr 318d66195c1SJeremy Kerr rc = tty_find_device(console); 319d66195c1SJeremy Kerr if (rc) 320d66195c1SJeremy Kerr return rc; 321d66195c1SJeremy Kerr 322d66195c1SJeremy Kerr rc = tty_init_io(console); 323d66195c1SJeremy Kerr return rc; 324d66195c1SJeremy Kerr } 325d66195c1SJeremy Kerr 3261a0e03b4SJeremy Kerr 3271a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 328d831f960SJeremy Kerr { 3291a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 330d831f960SJeremy Kerr } 331d831f960SJeremy Kerr 332f9c8f6caSCheng C Yang static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 333f9c8f6caSCheng C Yang sd_bus_error *err) 334f9c8f6caSCheng C Yang { 335f9c8f6caSCheng C Yang struct console *console = userdata; 336f9c8f6caSCheng C Yang uint32_t baudrate; 337f9c8f6caSCheng C Yang speed_t speed; 338f9c8f6caSCheng C Yang int r; 339f9c8f6caSCheng C Yang 340f9c8f6caSCheng C Yang if (!console) { 341f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 342f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", 0); 343f9c8f6caSCheng C Yang } 344f9c8f6caSCheng C Yang 345f9c8f6caSCheng C Yang r = sd_bus_message_read(msg, "u", &baudrate); 346f9c8f6caSCheng C Yang if (r < 0) { 347f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 348f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 349f9c8f6caSCheng C Yang } 350f9c8f6caSCheng C Yang 351f9c8f6caSCheng C Yang speed = parse_int_to_baud(baudrate); 352f9c8f6caSCheng C Yang if (!speed) { 353f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%u'", baudrate); 354f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 355f9c8f6caSCheng C Yang } 356f9c8f6caSCheng C Yang 357f9c8f6caSCheng C Yang console->tty_baud = speed; 358f9c8f6caSCheng C Yang tty_change_baudrate(console); 359f9c8f6caSCheng C Yang 360f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", r); 361f9c8f6caSCheng C Yang } 362f9c8f6caSCheng C Yang 363fd048328SAndrew Jeffery static int get_handler(sd_bus *bus __attribute__((unused)), 364fd048328SAndrew Jeffery const char *path __attribute__((unused)), 365fd048328SAndrew Jeffery const char *interface __attribute__((unused)), 366fd048328SAndrew Jeffery const char *property __attribute__((unused)), 367fd048328SAndrew Jeffery sd_bus_message *reply, void *userdata, 368fd048328SAndrew Jeffery sd_bus_error *error __attribute__((unused))) { 369f9c8f6caSCheng C Yang struct console *console = userdata; 370f9c8f6caSCheng C Yang uint32_t baudrate; 371f9c8f6caSCheng C Yang int r; 372f9c8f6caSCheng C Yang 373f9c8f6caSCheng C Yang baudrate = parse_baud_to_int(console->tty_baud); 374f9c8f6caSCheng C Yang if (!baudrate) 375f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 376f9c8f6caSCheng C Yang 377f9c8f6caSCheng C Yang r = sd_bus_message_append(reply, "u", baudrate); 378f9c8f6caSCheng C Yang 379f9c8f6caSCheng C Yang return r; 380f9c8f6caSCheng C Yang } 381f9c8f6caSCheng C Yang 382f9c8f6caSCheng C Yang static const sd_bus_vtable console_vtable[] = { 383f9c8f6caSCheng C Yang SD_BUS_VTABLE_START(0), 384f9c8f6caSCheng C Yang SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 385f9c8f6caSCheng C Yang SD_BUS_VTABLE_UNPRIVILEGED), 386f9c8f6caSCheng C Yang SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 387f9c8f6caSCheng C Yang SD_BUS_VTABLE_END,}; 388f9c8f6caSCheng C Yang 389fd048328SAndrew Jeffery static void dbus_init(struct console *console, struct config *config __attribute__((unused))) 390f9c8f6caSCheng C Yang { 391f9c8f6caSCheng C Yang int dbus_poller = 0; 392f9c8f6caSCheng C Yang int fd, r; 393f9c8f6caSCheng C Yang 394f9c8f6caSCheng C Yang if (!console) { 395f9c8f6caSCheng C Yang warnx("Couldn't get valid console"); 396f9c8f6caSCheng C Yang return; 397f9c8f6caSCheng C Yang } 398f9c8f6caSCheng C Yang 399f9c8f6caSCheng C Yang r = sd_bus_default_system(&console->bus); 400f9c8f6caSCheng C Yang if (r < 0) { 401f9c8f6caSCheng C Yang warnx("Failed to connect to system bus: %s", strerror(-r)); 402f9c8f6caSCheng C Yang return; 403f9c8f6caSCheng C Yang } 404f9c8f6caSCheng C Yang 405f9c8f6caSCheng C Yang r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 406f9c8f6caSCheng C Yang console_vtable, console); 407f9c8f6caSCheng C Yang if (r < 0) { 408f9c8f6caSCheng C Yang warnx("Failed to issue method call: %s", strerror(-r)); 409f9c8f6caSCheng C Yang return; 410f9c8f6caSCheng C Yang } 411f9c8f6caSCheng C Yang 412f9c8f6caSCheng C Yang r = sd_bus_request_name(console->bus, DBUS_NAME, SD_BUS_NAME_ALLOW_REPLACEMENT 413f9c8f6caSCheng C Yang |SD_BUS_NAME_REPLACE_EXISTING); 414f9c8f6caSCheng C Yang if (r < 0) { 415f9c8f6caSCheng C Yang warnx("Failed to acquire service name: %s", strerror(-r)); 416f9c8f6caSCheng C Yang return; 417f9c8f6caSCheng C Yang } 418f9c8f6caSCheng C Yang 419f9c8f6caSCheng C Yang fd = sd_bus_get_fd(console->bus); 420f9c8f6caSCheng C Yang if (fd < 0) { 421f9c8f6caSCheng C Yang warnx("Couldn't get the bus file descriptor"); 422f9c8f6caSCheng C Yang return; 423f9c8f6caSCheng C Yang } 424f9c8f6caSCheng C Yang 425f9c8f6caSCheng C Yang dbus_poller = POLLFD_DBUS; 426f9c8f6caSCheng C Yang 427f9c8f6caSCheng C Yang console->pollfds[dbus_poller].fd = fd; 428f9c8f6caSCheng C Yang console->pollfds[dbus_poller].events = POLLIN; 429f9c8f6caSCheng C Yang } 430f9c8f6caSCheng C Yang 431d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 432d831f960SJeremy Kerr { 4331a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 4341a0e03b4SJeremy Kerr struct handler *handler; 435021b91f0SJeremy Kerr int i, rc; 436d831f960SJeremy Kerr 4371a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4381a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 439d831f960SJeremy Kerr 4401a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 4411a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 442d831f960SJeremy Kerr 4431a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4441a0e03b4SJeremy Kerr handler = console->handlers[i]; 4451a0e03b4SJeremy Kerr 446021b91f0SJeremy Kerr rc = 0; 4471a0e03b4SJeremy Kerr if (handler->init) 448021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 449021b91f0SJeremy Kerr 450021b91f0SJeremy Kerr handler->active = rc == 0; 451021b91f0SJeremy Kerr 452021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 453021b91f0SJeremy Kerr handler->active ? "" : "in"); 454d831f960SJeremy Kerr } 455d831f960SJeremy Kerr } 456d831f960SJeremy Kerr 4571a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 458d831f960SJeremy Kerr { 4591a0e03b4SJeremy Kerr struct handler *handler; 4601a0e03b4SJeremy Kerr int i; 4611a0e03b4SJeremy Kerr 4621a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4631a0e03b4SJeremy Kerr handler = console->handlers[i]; 464021b91f0SJeremy Kerr if (handler->fini && handler->active) 4651a0e03b4SJeremy Kerr handler->fini(handler); 4661a0e03b4SJeremy Kerr } 467d831f960SJeremy Kerr } 468d831f960SJeremy Kerr 4691cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 4701cecc5deSJohnathan Mantey { 4711cecc5deSJohnathan Mantey struct timespec t; 4721cecc5deSJohnathan Mantey int rc; 4731cecc5deSJohnathan Mantey 4741cecc5deSJohnathan Mantey /* 4751cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 4761cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 4771cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 4781cecc5deSJohnathan Mantey */ 4791cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 4801cecc5deSJohnathan Mantey if (rc) 4811cecc5deSJohnathan Mantey return rc; 4821cecc5deSJohnathan Mantey 4831cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 4841cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 4851cecc5deSJohnathan Mantey 4861cecc5deSJohnathan Mantey return 0; 4871cecc5deSJohnathan Mantey } 4881cecc5deSJohnathan Mantey 489f733c85aSJeremy Kerr struct ringbuffer_consumer *console_ringbuffer_consumer_register( 490f733c85aSJeremy Kerr struct console *console, 491f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 492d831f960SJeremy Kerr { 493f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 494d831f960SJeremy Kerr } 495d831f960SJeremy Kerr 49655c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 4971cecc5deSJohnathan Mantey struct handler *handler, poller_event_fn_t poller_fn, 4981cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 4991cecc5deSJohnathan Mantey int events, void *data) 500d831f960SJeremy Kerr { 501329a35f5SJeremy Kerr struct poller *poller; 502329a35f5SJeremy Kerr int n; 503329a35f5SJeremy Kerr 504329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 505329a35f5SJeremy Kerr poller->remove = false; 506329a35f5SJeremy Kerr poller->handler = handler; 5071cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5081cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 509329a35f5SJeremy Kerr poller->data = data; 510329a35f5SJeremy Kerr 511329a35f5SJeremy Kerr /* add one to our pollers array */ 512329a35f5SJeremy Kerr n = console->n_pollers++; 513329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 514329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 515329a35f5SJeremy Kerr 516329a35f5SJeremy Kerr console->pollers[n] = poller; 517329a35f5SJeremy Kerr 518329a35f5SJeremy Kerr /* increase pollfds array too */ 519329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 520329a35f5SJeremy Kerr sizeof(*console->pollfds) * 521f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers)); 522329a35f5SJeremy Kerr 523329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 524f9c8f6caSCheng C Yang memcpy(&console->pollfds[n+1], 525329a35f5SJeremy Kerr &console->pollfds[n], 526f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 527329a35f5SJeremy Kerr 528329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 529329a35f5SJeremy Kerr console->pollfds[n].events = events; 530329a35f5SJeremy Kerr 531329a35f5SJeremy Kerr return poller; 532329a35f5SJeremy Kerr } 533329a35f5SJeremy Kerr 53455c9712dSJeremy Kerr void console_poller_unregister(struct console *console, 535329a35f5SJeremy Kerr struct poller *poller) 536329a35f5SJeremy Kerr { 537329a35f5SJeremy Kerr int i; 538329a35f5SJeremy Kerr 539329a35f5SJeremy Kerr /* find the entry in our pollers array */ 540329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 541329a35f5SJeremy Kerr if (console->pollers[i] == poller) 542329a35f5SJeremy Kerr break; 543329a35f5SJeremy Kerr 544329a35f5SJeremy Kerr assert(i < console->n_pollers); 545329a35f5SJeremy Kerr 546329a35f5SJeremy Kerr console->n_pollers--; 547329a35f5SJeremy Kerr 548329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 549329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 550329a35f5SJeremy Kerr sizeof(*console->pollers) 551329a35f5SJeremy Kerr * (console->n_pollers - i)); 552329a35f5SJeremy Kerr 553329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 554329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 555329a35f5SJeremy Kerr 556329a35f5SJeremy Kerr /* ... and the pollfds array */ 557329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 558329a35f5SJeremy Kerr sizeof(*console->pollfds) * 559f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 560329a35f5SJeremy Kerr 561329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 562329a35f5SJeremy Kerr sizeof(*console->pollfds) * 563f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers)); 564329a35f5SJeremy Kerr 565329a35f5SJeremy Kerr 566329a35f5SJeremy Kerr free(poller); 567329a35f5SJeremy Kerr } 568329a35f5SJeremy Kerr 5696b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 5706b1fed27SJeremy Kerr int events) 5716b1fed27SJeremy Kerr { 5726b1fed27SJeremy Kerr int i; 5736b1fed27SJeremy Kerr 5746b1fed27SJeremy Kerr /* find the entry in our pollers array */ 5756b1fed27SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 5766b1fed27SJeremy Kerr if (console->pollers[i] == poller) 5776b1fed27SJeremy Kerr break; 5786b1fed27SJeremy Kerr 5796b1fed27SJeremy Kerr console->pollfds[i].events = events; 5806b1fed27SJeremy Kerr } 5816b1fed27SJeremy Kerr 582fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)), 583fd048328SAndrew Jeffery struct poller *poller, const struct timeval *tv) 5841cecc5deSJohnathan Mantey { 5851cecc5deSJohnathan Mantey struct timeval now; 5861cecc5deSJohnathan Mantey int rc; 5871cecc5deSJohnathan Mantey 5881cecc5deSJohnathan Mantey rc = get_current_time(&now); 5891cecc5deSJohnathan Mantey if (rc) 5901cecc5deSJohnathan Mantey return; 5911cecc5deSJohnathan Mantey 5921cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 5931cecc5deSJohnathan Mantey } 5941cecc5deSJohnathan Mantey 5951cecc5deSJohnathan Mantey static int get_poll_timeout(struct console *console, struct timeval *cur_time) 5961cecc5deSJohnathan Mantey { 5971cecc5deSJohnathan Mantey struct timeval *earliest, interval; 5981cecc5deSJohnathan Mantey struct poller *poller; 5991cecc5deSJohnathan Mantey int i; 6001cecc5deSJohnathan Mantey 6011cecc5deSJohnathan Mantey earliest = NULL; 6021cecc5deSJohnathan Mantey 6031cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 6041cecc5deSJohnathan Mantey poller = console->pollers[i]; 6051cecc5deSJohnathan Mantey 6061cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6071cecc5deSJohnathan Mantey (!earliest || 6081cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))){ 6091cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6101cecc5deSJohnathan Mantey // function to timeout. 6111cecc5deSJohnathan Mantey earliest = &poller->timeout; 6121cecc5deSJohnathan Mantey } 6131cecc5deSJohnathan Mantey } 6141cecc5deSJohnathan Mantey 6151cecc5deSJohnathan Mantey if (earliest) { 6161cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6171cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6181cecc5deSJohnathan Mantey * not elapsed */ 6191cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6201cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6211cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 6221cecc5deSJohnathan Mantey } else { 6231cecc5deSJohnathan Mantey /* return from poll immediately */ 6241cecc5deSJohnathan Mantey return 0; 6251cecc5deSJohnathan Mantey } 6261cecc5deSJohnathan Mantey } else { 6271cecc5deSJohnathan Mantey /* poll indefinitely */ 6281cecc5deSJohnathan Mantey return -1; 6291cecc5deSJohnathan Mantey } 6301cecc5deSJohnathan Mantey } 6311cecc5deSJohnathan Mantey 6321cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 633329a35f5SJeremy Kerr { 634329a35f5SJeremy Kerr struct poller *poller; 635329a35f5SJeremy Kerr struct pollfd *pollfd; 636329a35f5SJeremy Kerr enum poller_ret prc; 637329a35f5SJeremy Kerr int i, rc; 638d831f960SJeremy Kerr 6391a0e03b4SJeremy Kerr rc = 0; 6401a0e03b4SJeremy Kerr 641329a35f5SJeremy Kerr /* 642329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 643329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 644329a35f5SJeremy Kerr */ 645329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 646329a35f5SJeremy Kerr poller = console->pollers[i]; 647329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 6481cecc5deSJohnathan Mantey prc = POLLER_OK; 6491a0e03b4SJeremy Kerr 6501cecc5deSJohnathan Mantey /* process pending events... */ 6511cecc5deSJohnathan Mantey if (pollfd->revents) { 6521cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 653329a35f5SJeremy Kerr poller->data); 654329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 655329a35f5SJeremy Kerr rc = -1; 656329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 657329a35f5SJeremy Kerr poller->remove = true; 658329a35f5SJeremy Kerr } 659329a35f5SJeremy Kerr 6601cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 6611cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 6621cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 6631cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 6641cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 6651cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 6661cecc5deSJohnathan Mantey transmission. */ 6671cecc5deSJohnathan Mantey timerclear(&poller->timeout); 6681cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 6691cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 6701cecc5deSJohnathan Mantey rc = -1; 6711cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 6721cecc5deSJohnathan Mantey poller->remove = true; 6731cecc5deSJohnathan Mantey } 6741cecc5deSJohnathan Mantey } 6751cecc5deSJohnathan Mantey } 6761cecc5deSJohnathan Mantey 677329a35f5SJeremy Kerr /** 678329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 679329a35f5SJeremy Kerr * the array will have changed 680329a35f5SJeremy Kerr */ 681329a35f5SJeremy Kerr for (;;) { 682329a35f5SJeremy Kerr bool removed = false; 683329a35f5SJeremy Kerr 684329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 685329a35f5SJeremy Kerr poller = console->pollers[i]; 686329a35f5SJeremy Kerr if (poller->remove) { 68755c9712dSJeremy Kerr console_poller_unregister(console, poller); 688329a35f5SJeremy Kerr removed = true; 689329a35f5SJeremy Kerr break; 690329a35f5SJeremy Kerr } 691329a35f5SJeremy Kerr } 692329a35f5SJeremy Kerr if (!removed) 693329a35f5SJeremy Kerr break; 6941a0e03b4SJeremy Kerr } 6951a0e03b4SJeremy Kerr 6961a0e03b4SJeremy Kerr return rc; 6971a0e03b4SJeremy Kerr } 6981a0e03b4SJeremy Kerr 699769cee1aSJeremy Kerr static void sighandler(int signal) 700769cee1aSJeremy Kerr { 701769cee1aSJeremy Kerr if (signal == SIGINT) 702769cee1aSJeremy Kerr sigint = true; 703769cee1aSJeremy Kerr } 704769cee1aSJeremy Kerr 7051a0e03b4SJeremy Kerr int run_console(struct console *console) 7061a0e03b4SJeremy Kerr { 707769cee1aSJeremy Kerr sighandler_t sighandler_save; 7081cecc5deSJohnathan Mantey struct timeval tv; 7091cecc5deSJohnathan Mantey int rc, timeout; 710d831f960SJeremy Kerr 711769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 712769cee1aSJeremy Kerr 713769cee1aSJeremy Kerr rc = 0; 714769cee1aSJeremy Kerr 715d831f960SJeremy Kerr for (;;) { 716d831f960SJeremy Kerr uint8_t buf[4096]; 717d831f960SJeremy Kerr 7181764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7191764145dSJeremy Kerr 720769cee1aSJeremy Kerr if (sigint) { 721769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 722769cee1aSJeremy Kerr break; 723769cee1aSJeremy Kerr } 724769cee1aSJeremy Kerr 7251cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7261cecc5deSJohnathan Mantey if (rc) { 7271cecc5deSJohnathan Mantey warn("Failed to read current time"); 7281cecc5deSJohnathan Mantey break; 7291cecc5deSJohnathan Mantey } 7301cecc5deSJohnathan Mantey 7311cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7321cecc5deSJohnathan Mantey 733329a35f5SJeremy Kerr rc = poll(console->pollfds, 7341cecc5deSJohnathan Mantey console->n_pollers + MAX_INTERNAL_POLLFD, 7351cecc5deSJohnathan Mantey timeout); 7361cecc5deSJohnathan Mantey 737d831f960SJeremy Kerr if (rc < 0) { 738769cee1aSJeremy Kerr if (errno == EINTR) { 739769cee1aSJeremy Kerr continue; 740769cee1aSJeremy Kerr } else { 741d831f960SJeremy Kerr warn("poll error"); 742769cee1aSJeremy Kerr break; 743769cee1aSJeremy Kerr } 744d831f960SJeremy Kerr } 745d831f960SJeremy Kerr 746329a35f5SJeremy Kerr /* process internal fd first */ 747329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 7481a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 749d831f960SJeremy Kerr if (rc <= 0) { 750d831f960SJeremy Kerr warn("Error reading from tty device"); 751769cee1aSJeremy Kerr rc = -1; 752769cee1aSJeremy Kerr break; 753d831f960SJeremy Kerr } 754f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 7551a0e03b4SJeremy Kerr if (rc) 756769cee1aSJeremy Kerr break; 757d831f960SJeremy Kerr } 758d831f960SJeremy Kerr 759f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 760f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 761f9c8f6caSCheng C Yang } 762f9c8f6caSCheng C Yang 763329a35f5SJeremy Kerr /* ... and then the pollers */ 7641cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 7651a0e03b4SJeremy Kerr if (rc) 766769cee1aSJeremy Kerr break; 7671a0e03b4SJeremy Kerr } 768769cee1aSJeremy Kerr 769769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 770f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 771769cee1aSJeremy Kerr 772769cee1aSJeremy Kerr return rc ? -1 : 0; 7731a0e03b4SJeremy Kerr } 774d831f960SJeremy Kerr static const struct option options[] = { 775d66195c1SJeremy Kerr { "config", required_argument, 0, 'c'}, 776f5858b5bSJoel Stanley { 0, 0, 0, 0}, 777d831f960SJeremy Kerr }; 778d831f960SJeremy Kerr 779d831f960SJeremy Kerr int main(int argc, char **argv) 780d831f960SJeremy Kerr { 781d66195c1SJeremy Kerr const char *config_filename = NULL; 7826221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 7831a0e03b4SJeremy Kerr struct console *console; 784d66195c1SJeremy Kerr struct config *config; 785d66195c1SJeremy Kerr int rc; 786d831f960SJeremy Kerr 787957818b4SJeremy Kerr rc = -1; 788d831f960SJeremy Kerr 789d831f960SJeremy Kerr for (;;) { 790d831f960SJeremy Kerr int c, idx; 791d831f960SJeremy Kerr 792d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 793d831f960SJeremy Kerr if (c == -1) 794d831f960SJeremy Kerr break; 795d831f960SJeremy Kerr 796d831f960SJeremy Kerr switch (c) { 797d66195c1SJeremy Kerr case 'c': 798d66195c1SJeremy Kerr config_filename = optarg; 799d831f960SJeremy Kerr break; 800d831f960SJeremy Kerr case 'h': 801d831f960SJeremy Kerr case '?': 802d831f960SJeremy Kerr usage(argv[0]); 803d66195c1SJeremy Kerr return EXIT_SUCCESS; 804d831f960SJeremy Kerr } 805d831f960SJeremy Kerr } 806d831f960SJeremy Kerr 80791dde14eSAndrew Jeffery if (optind < argc) 8086221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8096221ce94SVishwanatha Subbanna 810d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 811d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 812f9c8f6caSCheng C Yang console->pollfds = calloc(MAX_INTERNAL_POLLFD, 813329a35f5SJeremy Kerr sizeof(*console->pollfds)); 814f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 815329a35f5SJeremy Kerr 816d66195c1SJeremy Kerr config = config_init(config_filename); 817d66195c1SJeremy Kerr if (!config) { 818d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 819d66195c1SJeremy Kerr goto out_free; 820d831f960SJeremy Kerr } 821d831f960SJeremy Kerr 82291dde14eSAndrew Jeffery if (!config_tty_kname) 82391dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 82491dde14eSAndrew Jeffery 82591dde14eSAndrew Jeffery if (!config_tty_kname) { 82691dde14eSAndrew Jeffery warnx("No TTY device specified"); 82791dde14eSAndrew Jeffery usage(argv[0]); 82891dde14eSAndrew Jeffery return EXIT_FAILURE; 82991dde14eSAndrew Jeffery } 83091dde14eSAndrew Jeffery 8316221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 8326221ce94SVishwanatha Subbanna 833d66195c1SJeremy Kerr rc = tty_init(console, config); 83417217845SJeremy Kerr if (rc) 835d66195c1SJeremy Kerr goto out_config_fini; 836d831f960SJeremy Kerr 837f9c8f6caSCheng C Yang dbus_init(console, config); 838f9c8f6caSCheng C Yang 839d47963e5SJeremy Kerr handlers_init(console, config); 840d831f960SJeremy Kerr 8411a0e03b4SJeremy Kerr rc = run_console(console); 842d831f960SJeremy Kerr 8431a0e03b4SJeremy Kerr handlers_fini(console); 844d831f960SJeremy Kerr 845d66195c1SJeremy Kerr out_config_fini: 846d66195c1SJeremy Kerr config_fini(config); 847d66195c1SJeremy Kerr 848957818b4SJeremy Kerr out_free: 84989ea8198SJeremy Kerr free(console->pollers); 85089ea8198SJeremy Kerr free(console->pollfds); 8511a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 8521a0e03b4SJeremy Kerr free(console->tty_dev); 8531a0e03b4SJeremy Kerr free(console); 854d831f960SJeremy Kerr 855d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 856d831f960SJeremy Kerr } 857