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); 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); 13345ad7676SYi Li goto out_free; 13445ad7676SYi Li } 13545ad7676SYi Li 13645ad7676SYi Li rc = asprintf(&tty_class_device_link, 13745ad7676SYi Li "/sys/class/tty/%s", 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); 14417217845SJeremy Kerr goto out_free; 14517217845SJeremy Kerr } 14617217845SJeremy Kerr 14717217845SJeremy Kerr rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir); 14817217845SJeremy Kerr if (rc < 0) 14917217845SJeremy Kerr goto out_free; 15017217845SJeremy Kerr 1511a0e03b4SJeremy Kerr console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL); 1521a0e03b4SJeremy Kerr if (!console->tty_sysfs_devnode) 15345ad7676SYi Li warn("Can't find parent device for %s", tty_kname_real); 15417217845SJeremy Kerr 15545ad7676SYi Li rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real); 15617217845SJeremy Kerr if (rc < 0) 15717217845SJeremy Kerr goto out_free; 15817217845SJeremy Kerr 15917217845SJeremy Kerr rc = 0; 16017217845SJeremy Kerr 16117217845SJeremy Kerr out_free: 16217217845SJeremy Kerr free(tty_class_device_link); 16317217845SJeremy Kerr free(tty_device_tty_dir); 16417217845SJeremy Kerr free(tty_device_reldir); 16545ad7676SYi Li free(tty_path_input); 16645ad7676SYi Li free(tty_path_input_real); 16717217845SJeremy Kerr return rc; 16817217845SJeremy Kerr } 16917217845SJeremy Kerr 1701a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name, 171957818b4SJeremy Kerr int value) 172957818b4SJeremy Kerr { 173957818b4SJeremy Kerr char *path; 174957818b4SJeremy Kerr FILE *fp; 175957818b4SJeremy Kerr int rc; 176957818b4SJeremy Kerr 1771a0e03b4SJeremy Kerr rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name); 178957818b4SJeremy Kerr if (rc < 0) 179957818b4SJeremy Kerr return -1; 180957818b4SJeremy Kerr 181957818b4SJeremy Kerr fp = fopen(path, "w"); 182957818b4SJeremy Kerr if (!fp) { 183957818b4SJeremy Kerr warn("Can't access attribute %s on device %s", 1841a0e03b4SJeremy Kerr name, console->tty_kname); 185957818b4SJeremy Kerr rc = -1; 186957818b4SJeremy Kerr goto out_free; 187957818b4SJeremy Kerr } 188957818b4SJeremy Kerr setvbuf(fp, NULL, _IONBF, 0); 189957818b4SJeremy Kerr 190957818b4SJeremy Kerr rc = fprintf(fp, "0x%x", value); 191957818b4SJeremy Kerr if (rc < 0) 192957818b4SJeremy Kerr warn("Error writing to %s attribute of device %s", 1931a0e03b4SJeremy Kerr name, console->tty_kname); 194957818b4SJeremy Kerr fclose(fp); 195957818b4SJeremy Kerr 196957818b4SJeremy Kerr 197957818b4SJeremy Kerr 198957818b4SJeremy Kerr out_free: 199957818b4SJeremy Kerr free(path); 200957818b4SJeremy Kerr return rc; 201957818b4SJeremy Kerr } 202957818b4SJeremy Kerr 203d831f960SJeremy Kerr /** 204c7fbcd48SBenjamin Fair * Set termios attributes on the console tty. 20554e9569dSJeremy Kerr */ 20654e9569dSJeremy Kerr static void tty_init_termios(struct console *console) 20754e9569dSJeremy Kerr { 20854e9569dSJeremy Kerr struct termios termios; 20954e9569dSJeremy Kerr int rc; 21054e9569dSJeremy Kerr 21154e9569dSJeremy Kerr rc = tcgetattr(console->tty_fd, &termios); 21254e9569dSJeremy Kerr if (rc) { 21354e9569dSJeremy Kerr warn("Can't read tty termios"); 21454e9569dSJeremy Kerr return; 21554e9569dSJeremy Kerr } 21654e9569dSJeremy Kerr 217c7fbcd48SBenjamin Fair if (console->tty_baud) { 218c7fbcd48SBenjamin Fair if (cfsetspeed(&termios, console->tty_baud) < 0) 219c7fbcd48SBenjamin Fair warn("Couldn't set speeds for %s", console->tty_kname); 220c7fbcd48SBenjamin Fair } 221c7fbcd48SBenjamin Fair 222c7fbcd48SBenjamin Fair /* Set console to raw mode: we don't want any processing to occur on 223c7fbcd48SBenjamin Fair * the underlying terminal input/output. 224c7fbcd48SBenjamin Fair */ 22554e9569dSJeremy Kerr cfmakeraw(&termios); 226c7fbcd48SBenjamin Fair 22754e9569dSJeremy Kerr rc = tcsetattr(console->tty_fd, TCSANOW, &termios); 22854e9569dSJeremy Kerr if (rc) 229c7fbcd48SBenjamin Fair warn("Can't set terminal options for %s", console->tty_kname); 23054e9569dSJeremy Kerr } 23154e9569dSJeremy Kerr 232f9c8f6caSCheng C Yang 233f9c8f6caSCheng C Yang static void tty_change_baudrate(struct console *console) 234f9c8f6caSCheng C Yang { 235f9c8f6caSCheng C Yang struct handler *handler; 236f9c8f6caSCheng C Yang int i, rc; 237f9c8f6caSCheng C Yang 238f9c8f6caSCheng C Yang tty_init_termios(console); 239f9c8f6caSCheng C Yang 240f9c8f6caSCheng C Yang for (i = 0; i < console->n_handlers; i++) { 241f9c8f6caSCheng C Yang handler = console->handlers[i]; 242f9c8f6caSCheng C Yang if (!handler->baudrate) 243f9c8f6caSCheng C Yang continue; 244f9c8f6caSCheng C Yang 245f9c8f6caSCheng C Yang rc = handler->baudrate(handler, console->tty_baud); 246f9c8f6caSCheng C Yang if (rc) 247f9c8f6caSCheng C Yang warnx("Can't set terminal baudrate for handler %s", 248f9c8f6caSCheng C Yang handler->name); 249f9c8f6caSCheng C Yang } 250f9c8f6caSCheng C Yang } 251f9c8f6caSCheng C Yang 25254e9569dSJeremy Kerr /** 253d831f960SJeremy Kerr * Open and initialise the serial device 254d831f960SJeremy Kerr */ 2551a0e03b4SJeremy Kerr static int tty_init_io(struct console *console) 256d831f960SJeremy Kerr { 2571a0e03b4SJeremy Kerr if (console->tty_sirq) 2581a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "sirq", console->tty_sirq); 2591a0e03b4SJeremy Kerr if (console->tty_lpc_addr) 2601a0e03b4SJeremy Kerr tty_set_sysfs_attr(console, "lpc_address", 2611a0e03b4SJeremy Kerr console->tty_lpc_addr); 262957818b4SJeremy Kerr 2631a0e03b4SJeremy Kerr console->tty_fd = open(console->tty_dev, O_RDWR); 2641a0e03b4SJeremy Kerr if (console->tty_fd <= 0) { 2651a0e03b4SJeremy Kerr warn("Can't open tty %s", console->tty_dev); 266d831f960SJeremy Kerr return -1; 267d831f960SJeremy Kerr } 268d831f960SJeremy Kerr 269d831f960SJeremy Kerr /* Disable character delay. We may want to later enable this when 270d831f960SJeremy Kerr * we detect larger amounts of data 271d831f960SJeremy Kerr */ 2721a0e03b4SJeremy Kerr fcntl(console->tty_fd, F_SETFL, FNDELAY); 273d831f960SJeremy Kerr 27454e9569dSJeremy Kerr tty_init_termios(console); 27554e9569dSJeremy Kerr 276329a35f5SJeremy Kerr console->pollfds[console->n_pollers].fd = console->tty_fd; 277329a35f5SJeremy Kerr console->pollfds[console->n_pollers].events = POLLIN; 278329a35f5SJeremy Kerr 279d831f960SJeremy Kerr return 0; 280d831f960SJeremy Kerr } 281d831f960SJeremy Kerr 282d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config) 283d66195c1SJeremy Kerr { 284d66195c1SJeremy Kerr const char *val; 285d66195c1SJeremy Kerr char *endp; 286d66195c1SJeremy Kerr int rc; 287d66195c1SJeremy Kerr 288d66195c1SJeremy Kerr val = config_get_value(config, "lpc-address"); 289d66195c1SJeremy Kerr if (val) { 290d66195c1SJeremy Kerr console->tty_lpc_addr = strtoul(val, &endp, 0); 291d66195c1SJeremy Kerr if (endp == optarg) { 292d66195c1SJeremy Kerr warn("Invalid LPC address: '%s'", val); 293d66195c1SJeremy Kerr return -1; 294d66195c1SJeremy Kerr } 295d66195c1SJeremy Kerr } 296d66195c1SJeremy Kerr 297d66195c1SJeremy Kerr val = config_get_value(config, "sirq"); 298d66195c1SJeremy Kerr if (val) { 299d66195c1SJeremy Kerr console->tty_sirq = strtoul(val, &endp, 0); 300d66195c1SJeremy Kerr if (endp == optarg) 301d66195c1SJeremy Kerr warn("Invalid sirq: '%s'", val); 302d66195c1SJeremy Kerr } 303d66195c1SJeremy Kerr 304c7fbcd48SBenjamin Fair val = config_get_value(config, "baud"); 305c7fbcd48SBenjamin Fair if (val) { 306c7fbcd48SBenjamin Fair if (config_parse_baud(&console->tty_baud, val)) 307c7fbcd48SBenjamin Fair warnx("Invalid baud rate: '%s'", val); 308c7fbcd48SBenjamin Fair } 309c7fbcd48SBenjamin Fair 310d66195c1SJeremy Kerr if (!console->tty_kname) { 311d66195c1SJeremy Kerr warnx("Error: No TTY device specified"); 312d66195c1SJeremy Kerr return -1; 313d66195c1SJeremy Kerr } 314d66195c1SJeremy Kerr 315d66195c1SJeremy Kerr rc = tty_find_device(console); 316d66195c1SJeremy Kerr if (rc) 317d66195c1SJeremy Kerr return rc; 318d66195c1SJeremy Kerr 319d66195c1SJeremy Kerr rc = tty_init_io(console); 320d66195c1SJeremy Kerr return rc; 321d66195c1SJeremy Kerr } 322d66195c1SJeremy Kerr 3231a0e03b4SJeremy Kerr 3241a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len) 325d831f960SJeremy Kerr { 3261a0e03b4SJeremy Kerr return write_buf_to_fd(console->tty_fd, data, len); 327d831f960SJeremy Kerr } 328d831f960SJeremy Kerr 329f9c8f6caSCheng C Yang static int method_set_baud_rate(sd_bus_message *msg, void *userdata, 330f9c8f6caSCheng C Yang sd_bus_error *err) 331f9c8f6caSCheng C Yang { 332f9c8f6caSCheng C Yang struct console *console = userdata; 333f9c8f6caSCheng C Yang uint32_t baudrate; 334f9c8f6caSCheng C Yang speed_t speed; 335f9c8f6caSCheng C Yang int r; 336f9c8f6caSCheng C Yang 337f9c8f6caSCheng C Yang if (!console) { 338f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Internal error"); 339f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", 0); 340f9c8f6caSCheng C Yang } 341f9c8f6caSCheng C Yang 342f9c8f6caSCheng C Yang r = sd_bus_message_read(msg, "u", &baudrate); 343f9c8f6caSCheng C Yang if (r < 0) { 344f9c8f6caSCheng C Yang sd_bus_error_set_const(err, DBUS_ERR, "Bad message"); 345f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 346f9c8f6caSCheng C Yang } 347f9c8f6caSCheng C Yang 348f9c8f6caSCheng C Yang speed = parse_int_to_baud(baudrate); 349f9c8f6caSCheng C Yang if (!speed) { 350f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%u'", baudrate); 351f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", -EINVAL); 352f9c8f6caSCheng C Yang } 353f9c8f6caSCheng C Yang 354f9c8f6caSCheng C Yang console->tty_baud = speed; 355f9c8f6caSCheng C Yang tty_change_baudrate(console); 356f9c8f6caSCheng C Yang 357f9c8f6caSCheng C Yang return sd_bus_reply_method_return(msg, "x", r); 358f9c8f6caSCheng C Yang } 359f9c8f6caSCheng C Yang 360f9c8f6caSCheng C Yang static int get_handler(sd_bus *bus, const char *path, const char *interface, 361f9c8f6caSCheng C Yang const char *property, sd_bus_message *reply, void *userdata, 362f9c8f6caSCheng C Yang sd_bus_error *error) { 363f9c8f6caSCheng C Yang struct console *console = userdata; 364f9c8f6caSCheng C Yang uint32_t baudrate; 365f9c8f6caSCheng C Yang int r; 366f9c8f6caSCheng C Yang 367f9c8f6caSCheng C Yang baudrate = parse_baud_to_int(console->tty_baud); 368f9c8f6caSCheng C Yang if (!baudrate) 369f9c8f6caSCheng C Yang warnx("Invalid baud rate: '%d'", console->tty_baud); 370f9c8f6caSCheng C Yang 371f9c8f6caSCheng C Yang r = sd_bus_message_append(reply, "u", baudrate); 372f9c8f6caSCheng C Yang 373f9c8f6caSCheng C Yang return r; 374f9c8f6caSCheng C Yang } 375f9c8f6caSCheng C Yang 376f9c8f6caSCheng C Yang static const sd_bus_vtable console_vtable[] = { 377f9c8f6caSCheng C Yang SD_BUS_VTABLE_START(0), 378f9c8f6caSCheng C Yang SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate, 379f9c8f6caSCheng C Yang SD_BUS_VTABLE_UNPRIVILEGED), 380f9c8f6caSCheng C Yang SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0), 381f9c8f6caSCheng C Yang SD_BUS_VTABLE_END,}; 382f9c8f6caSCheng C Yang 383f9c8f6caSCheng C Yang static void dbus_init(struct console *console, struct config *config) 384f9c8f6caSCheng C Yang { 385f9c8f6caSCheng C Yang int dbus_poller = 0; 386f9c8f6caSCheng C Yang int fd, r; 387f9c8f6caSCheng C Yang 388f9c8f6caSCheng C Yang if (!console) { 389f9c8f6caSCheng C Yang warnx("Couldn't get valid console"); 390f9c8f6caSCheng C Yang return; 391f9c8f6caSCheng C Yang } 392f9c8f6caSCheng C Yang 393f9c8f6caSCheng C Yang r = sd_bus_default_system(&console->bus); 394f9c8f6caSCheng C Yang if (r < 0) { 395f9c8f6caSCheng C Yang warnx("Failed to connect to system bus: %s", strerror(-r)); 396f9c8f6caSCheng C Yang return; 397f9c8f6caSCheng C Yang } 398f9c8f6caSCheng C Yang 399f9c8f6caSCheng C Yang r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME, 400f9c8f6caSCheng C Yang console_vtable, console); 401f9c8f6caSCheng C Yang if (r < 0) { 402f9c8f6caSCheng C Yang warnx("Failed to issue method call: %s", strerror(-r)); 403f9c8f6caSCheng C Yang return; 404f9c8f6caSCheng C Yang } 405f9c8f6caSCheng C Yang 406f9c8f6caSCheng C Yang r = sd_bus_request_name(console->bus, DBUS_NAME, SD_BUS_NAME_ALLOW_REPLACEMENT 407f9c8f6caSCheng C Yang |SD_BUS_NAME_REPLACE_EXISTING); 408f9c8f6caSCheng C Yang if (r < 0) { 409f9c8f6caSCheng C Yang warnx("Failed to acquire service name: %s", strerror(-r)); 410f9c8f6caSCheng C Yang return; 411f9c8f6caSCheng C Yang } 412f9c8f6caSCheng C Yang 413f9c8f6caSCheng C Yang fd = sd_bus_get_fd(console->bus); 414f9c8f6caSCheng C Yang if (fd < 0) { 415f9c8f6caSCheng C Yang warnx("Couldn't get the bus file descriptor"); 416f9c8f6caSCheng C Yang return; 417f9c8f6caSCheng C Yang } 418f9c8f6caSCheng C Yang 419f9c8f6caSCheng C Yang dbus_poller = POLLFD_DBUS; 420f9c8f6caSCheng C Yang 421f9c8f6caSCheng C Yang console->pollfds[dbus_poller].fd = fd; 422f9c8f6caSCheng C Yang console->pollfds[dbus_poller].events = POLLIN; 423f9c8f6caSCheng C Yang } 424f9c8f6caSCheng C Yang 425d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config) 426d831f960SJeremy Kerr { 4271a0e03b4SJeremy Kerr extern struct handler *__start_handlers, *__stop_handlers; 4281a0e03b4SJeremy Kerr struct handler *handler; 429021b91f0SJeremy Kerr int i, rc; 430d831f960SJeremy Kerr 4311a0e03b4SJeremy Kerr console->n_handlers = &__stop_handlers - &__start_handlers; 4321a0e03b4SJeremy Kerr console->handlers = &__start_handlers; 433d831f960SJeremy Kerr 4341a0e03b4SJeremy Kerr printf("%d handler%s\n", console->n_handlers, 4351a0e03b4SJeremy Kerr console->n_handlers == 1 ? "" : "s"); 436d831f960SJeremy Kerr 4371a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4381a0e03b4SJeremy Kerr handler = console->handlers[i]; 4391a0e03b4SJeremy Kerr 440021b91f0SJeremy Kerr rc = 0; 4411a0e03b4SJeremy Kerr if (handler->init) 442021b91f0SJeremy Kerr rc = handler->init(handler, console, config); 443021b91f0SJeremy Kerr 444021b91f0SJeremy Kerr handler->active = rc == 0; 445021b91f0SJeremy Kerr 446021b91f0SJeremy Kerr printf(" %s [%sactive]\n", handler->name, 447021b91f0SJeremy Kerr handler->active ? "" : "in"); 448d831f960SJeremy Kerr } 449d831f960SJeremy Kerr } 450d831f960SJeremy Kerr 4511a0e03b4SJeremy Kerr static void handlers_fini(struct console *console) 452d831f960SJeremy Kerr { 4531a0e03b4SJeremy Kerr struct handler *handler; 4541a0e03b4SJeremy Kerr int i; 4551a0e03b4SJeremy Kerr 4561a0e03b4SJeremy Kerr for (i = 0; i < console->n_handlers; i++) { 4571a0e03b4SJeremy Kerr handler = console->handlers[i]; 458021b91f0SJeremy Kerr if (handler->fini && handler->active) 4591a0e03b4SJeremy Kerr handler->fini(handler); 4601a0e03b4SJeremy Kerr } 461d831f960SJeremy Kerr } 462d831f960SJeremy Kerr 4631cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 4641cecc5deSJohnathan Mantey { 4651cecc5deSJohnathan Mantey struct timespec t; 4661cecc5deSJohnathan Mantey int rc; 4671cecc5deSJohnathan Mantey 4681cecc5deSJohnathan Mantey /* 4691cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 4701cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 4711cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 4721cecc5deSJohnathan Mantey */ 4731cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 4741cecc5deSJohnathan Mantey if (rc) 4751cecc5deSJohnathan Mantey return rc; 4761cecc5deSJohnathan Mantey 4771cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 4781cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 4791cecc5deSJohnathan Mantey 4801cecc5deSJohnathan Mantey return 0; 4811cecc5deSJohnathan Mantey } 4821cecc5deSJohnathan Mantey 483f733c85aSJeremy Kerr struct ringbuffer_consumer *console_ringbuffer_consumer_register( 484f733c85aSJeremy Kerr struct console *console, 485f733c85aSJeremy Kerr ringbuffer_poll_fn_t poll_fn, void *data) 486d831f960SJeremy Kerr { 487f733c85aSJeremy Kerr return ringbuffer_consumer_register(console->rb, poll_fn, data); 488d831f960SJeremy Kerr } 489d831f960SJeremy Kerr 49055c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console, 4911cecc5deSJohnathan Mantey struct handler *handler, poller_event_fn_t poller_fn, 4921cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 4931cecc5deSJohnathan Mantey int events, void *data) 494d831f960SJeremy Kerr { 495329a35f5SJeremy Kerr struct poller *poller; 496329a35f5SJeremy Kerr int n; 497329a35f5SJeremy Kerr 498329a35f5SJeremy Kerr poller = malloc(sizeof(*poller)); 499329a35f5SJeremy Kerr poller->remove = false; 500329a35f5SJeremy Kerr poller->handler = handler; 5011cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 5021cecc5deSJohnathan Mantey poller->timeout_fn = timeout_fn; 503329a35f5SJeremy Kerr poller->data = data; 504329a35f5SJeremy Kerr 505329a35f5SJeremy Kerr /* add one to our pollers array */ 506329a35f5SJeremy Kerr n = console->n_pollers++; 507329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 508329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 509329a35f5SJeremy Kerr 510329a35f5SJeremy Kerr console->pollers[n] = poller; 511329a35f5SJeremy Kerr 512329a35f5SJeremy Kerr /* increase pollfds array too */ 513329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 514329a35f5SJeremy Kerr sizeof(*console->pollfds) * 515f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers)); 516329a35f5SJeremy Kerr 517329a35f5SJeremy Kerr /* shift the end pollfds up by one */ 518f9c8f6caSCheng C Yang memcpy(&console->pollfds[n+1], 519329a35f5SJeremy Kerr &console->pollfds[n], 520f9c8f6caSCheng C Yang sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD); 521329a35f5SJeremy Kerr 522329a35f5SJeremy Kerr console->pollfds[n].fd = fd; 523329a35f5SJeremy Kerr console->pollfds[n].events = events; 524329a35f5SJeremy Kerr 525329a35f5SJeremy Kerr return poller; 526329a35f5SJeremy Kerr } 527329a35f5SJeremy Kerr 52855c9712dSJeremy Kerr void console_poller_unregister(struct console *console, 529329a35f5SJeremy Kerr struct poller *poller) 530329a35f5SJeremy Kerr { 531329a35f5SJeremy Kerr int i; 532329a35f5SJeremy Kerr 533329a35f5SJeremy Kerr /* find the entry in our pollers array */ 534329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 535329a35f5SJeremy Kerr if (console->pollers[i] == poller) 536329a35f5SJeremy Kerr break; 537329a35f5SJeremy Kerr 538329a35f5SJeremy Kerr assert(i < console->n_pollers); 539329a35f5SJeremy Kerr 540329a35f5SJeremy Kerr console->n_pollers--; 541329a35f5SJeremy Kerr 542329a35f5SJeremy Kerr /* remove the item from the pollers array... */ 543329a35f5SJeremy Kerr memmove(&console->pollers[i], &console->pollers[i+1], 544329a35f5SJeremy Kerr sizeof(*console->pollers) 545329a35f5SJeremy Kerr * (console->n_pollers - i)); 546329a35f5SJeremy Kerr 547329a35f5SJeremy Kerr console->pollers = realloc(console->pollers, 548329a35f5SJeremy Kerr sizeof(*console->pollers) * console->n_pollers); 549329a35f5SJeremy Kerr 550329a35f5SJeremy Kerr /* ... and the pollfds array */ 551329a35f5SJeremy Kerr memmove(&console->pollfds[i], &console->pollfds[i+1], 552329a35f5SJeremy Kerr sizeof(*console->pollfds) * 553f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers - i)); 554329a35f5SJeremy Kerr 555329a35f5SJeremy Kerr console->pollfds = realloc(console->pollfds, 556329a35f5SJeremy Kerr sizeof(*console->pollfds) * 557f9c8f6caSCheng C Yang (MAX_INTERNAL_POLLFD + console->n_pollers)); 558329a35f5SJeremy Kerr 559329a35f5SJeremy Kerr 560329a35f5SJeremy Kerr free(poller); 561329a35f5SJeremy Kerr } 562329a35f5SJeremy Kerr 5636b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller, 5646b1fed27SJeremy Kerr int events) 5656b1fed27SJeremy Kerr { 5666b1fed27SJeremy Kerr int i; 5676b1fed27SJeremy Kerr 5686b1fed27SJeremy Kerr /* find the entry in our pollers array */ 5696b1fed27SJeremy Kerr for (i = 0; i < console->n_pollers; i++) 5706b1fed27SJeremy Kerr if (console->pollers[i] == poller) 5716b1fed27SJeremy Kerr break; 5726b1fed27SJeremy Kerr 5736b1fed27SJeremy Kerr console->pollfds[i].events = events; 5746b1fed27SJeremy Kerr } 5756b1fed27SJeremy Kerr 5761cecc5deSJohnathan Mantey void console_poller_set_timeout(struct console *console, struct poller *poller, 5771cecc5deSJohnathan Mantey const struct timeval *tv) 5781cecc5deSJohnathan Mantey { 5791cecc5deSJohnathan Mantey struct timeval now; 5801cecc5deSJohnathan Mantey int rc; 5811cecc5deSJohnathan Mantey 5821cecc5deSJohnathan Mantey rc = get_current_time(&now); 5831cecc5deSJohnathan Mantey if (rc) 5841cecc5deSJohnathan Mantey return; 5851cecc5deSJohnathan Mantey 5861cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 5871cecc5deSJohnathan Mantey } 5881cecc5deSJohnathan Mantey 5891cecc5deSJohnathan Mantey static int get_poll_timeout(struct console *console, struct timeval *cur_time) 5901cecc5deSJohnathan Mantey { 5911cecc5deSJohnathan Mantey struct timeval *earliest, interval; 5921cecc5deSJohnathan Mantey struct poller *poller; 5931cecc5deSJohnathan Mantey int i; 5941cecc5deSJohnathan Mantey 5951cecc5deSJohnathan Mantey earliest = NULL; 5961cecc5deSJohnathan Mantey 5971cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 5981cecc5deSJohnathan Mantey poller = console->pollers[i]; 5991cecc5deSJohnathan Mantey 6001cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 6011cecc5deSJohnathan Mantey (!earliest || 6021cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))){ 6031cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 6041cecc5deSJohnathan Mantey // function to timeout. 6051cecc5deSJohnathan Mantey earliest = &poller->timeout; 6061cecc5deSJohnathan Mantey } 6071cecc5deSJohnathan Mantey } 6081cecc5deSJohnathan Mantey 6091cecc5deSJohnathan Mantey if (earliest) { 6101cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 6111cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 6121cecc5deSJohnathan Mantey * not elapsed */ 6131cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 6141cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 6151cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 6161cecc5deSJohnathan Mantey } else { 6171cecc5deSJohnathan Mantey /* return from poll immediately */ 6181cecc5deSJohnathan Mantey return 0; 6191cecc5deSJohnathan Mantey } 6201cecc5deSJohnathan Mantey } else { 6211cecc5deSJohnathan Mantey /* poll indefinitely */ 6221cecc5deSJohnathan Mantey return -1; 6231cecc5deSJohnathan Mantey } 6241cecc5deSJohnathan Mantey } 6251cecc5deSJohnathan Mantey 6261cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time) 627329a35f5SJeremy Kerr { 628329a35f5SJeremy Kerr struct poller *poller; 629329a35f5SJeremy Kerr struct pollfd *pollfd; 630329a35f5SJeremy Kerr enum poller_ret prc; 631329a35f5SJeremy Kerr int i, rc; 632d831f960SJeremy Kerr 6331a0e03b4SJeremy Kerr rc = 0; 6341a0e03b4SJeremy Kerr 635329a35f5SJeremy Kerr /* 636329a35f5SJeremy Kerr * Process poll events by iterating through the pollers and pollfds 637329a35f5SJeremy Kerr * in-step, calling any pollers that we've found revents for. 638329a35f5SJeremy Kerr */ 639329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 640329a35f5SJeremy Kerr poller = console->pollers[i]; 641329a35f5SJeremy Kerr pollfd = &console->pollfds[i]; 6421cecc5deSJohnathan Mantey prc = POLLER_OK; 6431a0e03b4SJeremy Kerr 6441cecc5deSJohnathan Mantey /* process pending events... */ 6451cecc5deSJohnathan Mantey if (pollfd->revents) { 6461cecc5deSJohnathan Mantey prc = poller->event_fn(poller->handler, pollfd->revents, 647329a35f5SJeremy Kerr poller->data); 648329a35f5SJeremy Kerr if (prc == POLLER_EXIT) 649329a35f5SJeremy Kerr rc = -1; 650329a35f5SJeremy Kerr else if (prc == POLLER_REMOVE) 651329a35f5SJeremy Kerr poller->remove = true; 652329a35f5SJeremy Kerr } 653329a35f5SJeremy Kerr 6541cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 6551cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 6561cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 6571cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 6581cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 6591cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 6601cecc5deSJohnathan Mantey transmission. */ 6611cecc5deSJohnathan Mantey timerclear(&poller->timeout); 6621cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 6631cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 6641cecc5deSJohnathan Mantey rc = -1; 6651cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 6661cecc5deSJohnathan Mantey poller->remove = true; 6671cecc5deSJohnathan Mantey } 6681cecc5deSJohnathan Mantey } 6691cecc5deSJohnathan Mantey } 6701cecc5deSJohnathan Mantey 671329a35f5SJeremy Kerr /** 672329a35f5SJeremy Kerr * Process deferred removals; restarting each time we unregister, as 673329a35f5SJeremy Kerr * the array will have changed 674329a35f5SJeremy Kerr */ 675329a35f5SJeremy Kerr for (;;) { 676329a35f5SJeremy Kerr bool removed = false; 677329a35f5SJeremy Kerr 678329a35f5SJeremy Kerr for (i = 0; i < console->n_pollers; i++) { 679329a35f5SJeremy Kerr poller = console->pollers[i]; 680329a35f5SJeremy Kerr if (poller->remove) { 68155c9712dSJeremy Kerr console_poller_unregister(console, poller); 682329a35f5SJeremy Kerr removed = true; 683329a35f5SJeremy Kerr break; 684329a35f5SJeremy Kerr } 685329a35f5SJeremy Kerr } 686329a35f5SJeremy Kerr if (!removed) 687329a35f5SJeremy Kerr break; 6881a0e03b4SJeremy Kerr } 6891a0e03b4SJeremy Kerr 6901a0e03b4SJeremy Kerr return rc; 6911a0e03b4SJeremy Kerr } 6921a0e03b4SJeremy Kerr 693769cee1aSJeremy Kerr static void sighandler(int signal) 694769cee1aSJeremy Kerr { 695769cee1aSJeremy Kerr if (signal == SIGINT) 696769cee1aSJeremy Kerr sigint = true; 697769cee1aSJeremy Kerr } 698769cee1aSJeremy Kerr 6991a0e03b4SJeremy Kerr int run_console(struct console *console) 7001a0e03b4SJeremy Kerr { 701769cee1aSJeremy Kerr sighandler_t sighandler_save; 7021cecc5deSJohnathan Mantey struct timeval tv; 7031cecc5deSJohnathan Mantey int rc, timeout; 704d831f960SJeremy Kerr 705769cee1aSJeremy Kerr sighandler_save = signal(SIGINT, sighandler); 706769cee1aSJeremy Kerr 707769cee1aSJeremy Kerr rc = 0; 708769cee1aSJeremy Kerr 709d831f960SJeremy Kerr for (;;) { 710d831f960SJeremy Kerr uint8_t buf[4096]; 711d831f960SJeremy Kerr 7121764145dSJeremy Kerr BUILD_ASSERT(sizeof(buf) <= buffer_size); 7131764145dSJeremy Kerr 714769cee1aSJeremy Kerr if (sigint) { 715769cee1aSJeremy Kerr fprintf(stderr, "Received interrupt, exiting\n"); 716769cee1aSJeremy Kerr break; 717769cee1aSJeremy Kerr } 718769cee1aSJeremy Kerr 7191cecc5deSJohnathan Mantey rc = get_current_time(&tv); 7201cecc5deSJohnathan Mantey if (rc) { 7211cecc5deSJohnathan Mantey warn("Failed to read current time"); 7221cecc5deSJohnathan Mantey break; 7231cecc5deSJohnathan Mantey } 7241cecc5deSJohnathan Mantey 7251cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 7261cecc5deSJohnathan Mantey 727329a35f5SJeremy Kerr rc = poll(console->pollfds, 7281cecc5deSJohnathan Mantey console->n_pollers + MAX_INTERNAL_POLLFD, 7291cecc5deSJohnathan Mantey timeout); 7301cecc5deSJohnathan Mantey 731d831f960SJeremy Kerr if (rc < 0) { 732769cee1aSJeremy Kerr if (errno == EINTR) { 733769cee1aSJeremy Kerr continue; 734769cee1aSJeremy Kerr } else { 735d831f960SJeremy Kerr warn("poll error"); 736769cee1aSJeremy Kerr break; 737769cee1aSJeremy Kerr } 738d831f960SJeremy Kerr } 739d831f960SJeremy Kerr 740329a35f5SJeremy Kerr /* process internal fd first */ 741329a35f5SJeremy Kerr if (console->pollfds[console->n_pollers].revents) { 7421a0e03b4SJeremy Kerr rc = read(console->tty_fd, buf, sizeof(buf)); 743d831f960SJeremy Kerr if (rc <= 0) { 744d831f960SJeremy Kerr warn("Error reading from tty device"); 745769cee1aSJeremy Kerr rc = -1; 746769cee1aSJeremy Kerr break; 747d831f960SJeremy Kerr } 748f733c85aSJeremy Kerr rc = ringbuffer_queue(console->rb, buf, rc); 7491a0e03b4SJeremy Kerr if (rc) 750769cee1aSJeremy Kerr break; 751d831f960SJeremy Kerr } 752d831f960SJeremy Kerr 753f9c8f6caSCheng C Yang if (console->pollfds[console->n_pollers + 1].revents) { 754f9c8f6caSCheng C Yang sd_bus_process(console->bus, NULL); 755f9c8f6caSCheng C Yang } 756f9c8f6caSCheng C Yang 757329a35f5SJeremy Kerr /* ... and then the pollers */ 7581cecc5deSJohnathan Mantey rc = call_pollers(console, &tv); 7591a0e03b4SJeremy Kerr if (rc) 760769cee1aSJeremy Kerr break; 7611a0e03b4SJeremy Kerr } 762769cee1aSJeremy Kerr 763769cee1aSJeremy Kerr signal(SIGINT, sighandler_save); 764f9c8f6caSCheng C Yang sd_bus_unref(console->bus); 765769cee1aSJeremy Kerr 766769cee1aSJeremy Kerr return rc ? -1 : 0; 7671a0e03b4SJeremy Kerr } 768d831f960SJeremy Kerr static const struct option options[] = { 769d66195c1SJeremy Kerr { "config", required_argument, 0, 'c'}, 770f5858b5bSJoel Stanley { 0, 0, 0, 0}, 771d831f960SJeremy Kerr }; 772d831f960SJeremy Kerr 773d831f960SJeremy Kerr int main(int argc, char **argv) 774d831f960SJeremy Kerr { 775d66195c1SJeremy Kerr const char *config_filename = NULL; 7766221ce94SVishwanatha Subbanna const char *config_tty_kname = NULL; 7771a0e03b4SJeremy Kerr struct console *console; 778d66195c1SJeremy Kerr struct config *config; 779d66195c1SJeremy Kerr int rc; 780d831f960SJeremy Kerr 781957818b4SJeremy Kerr rc = -1; 782d831f960SJeremy Kerr 783d831f960SJeremy Kerr for (;;) { 784d831f960SJeremy Kerr int c, idx; 785d831f960SJeremy Kerr 786d66195c1SJeremy Kerr c = getopt_long(argc, argv, "c:", options, &idx); 787d831f960SJeremy Kerr if (c == -1) 788d831f960SJeremy Kerr break; 789d831f960SJeremy Kerr 790d831f960SJeremy Kerr switch (c) { 791d66195c1SJeremy Kerr case 'c': 792d66195c1SJeremy Kerr config_filename = optarg; 793d831f960SJeremy Kerr break; 794d831f960SJeremy Kerr case 'h': 795d831f960SJeremy Kerr case '?': 796d831f960SJeremy Kerr usage(argv[0]); 797d66195c1SJeremy Kerr return EXIT_SUCCESS; 798d831f960SJeremy Kerr } 799d831f960SJeremy Kerr } 800d831f960SJeremy Kerr 801*91dde14eSAndrew Jeffery if (optind < argc) 8026221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8036221ce94SVishwanatha Subbanna 804d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 805d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 806f9c8f6caSCheng C Yang console->pollfds = calloc(MAX_INTERNAL_POLLFD, 807329a35f5SJeremy Kerr sizeof(*console->pollfds)); 808f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 809329a35f5SJeremy Kerr 810d66195c1SJeremy Kerr config = config_init(config_filename); 811d66195c1SJeremy Kerr if (!config) { 812d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 813d66195c1SJeremy Kerr goto out_free; 814d831f960SJeremy Kerr } 815d831f960SJeremy Kerr 816*91dde14eSAndrew Jeffery if (!config_tty_kname) 817*91dde14eSAndrew Jeffery config_tty_kname = config_get_value(config, "upstream-tty"); 818*91dde14eSAndrew Jeffery 819*91dde14eSAndrew Jeffery if (!config_tty_kname) { 820*91dde14eSAndrew Jeffery warnx("No TTY device specified"); 821*91dde14eSAndrew Jeffery usage(argv[0]); 822*91dde14eSAndrew Jeffery return EXIT_FAILURE; 823*91dde14eSAndrew Jeffery } 824*91dde14eSAndrew Jeffery 8256221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 8266221ce94SVishwanatha Subbanna 827d66195c1SJeremy Kerr rc = tty_init(console, config); 82817217845SJeremy Kerr if (rc) 829d66195c1SJeremy Kerr goto out_config_fini; 830d831f960SJeremy Kerr 831f9c8f6caSCheng C Yang dbus_init(console, config); 832f9c8f6caSCheng C Yang 833d47963e5SJeremy Kerr handlers_init(console, config); 834d831f960SJeremy Kerr 8351a0e03b4SJeremy Kerr rc = run_console(console); 836d831f960SJeremy Kerr 8371a0e03b4SJeremy Kerr handlers_fini(console); 838d831f960SJeremy Kerr 839d66195c1SJeremy Kerr out_config_fini: 840d66195c1SJeremy Kerr config_fini(config); 841d66195c1SJeremy Kerr 842957818b4SJeremy Kerr out_free: 84389ea8198SJeremy Kerr free(console->pollers); 84489ea8198SJeremy Kerr free(console->pollfds); 8451a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 8461a0e03b4SJeremy Kerr free(console->tty_dev); 8471a0e03b4SJeremy Kerr free(console); 848d831f960SJeremy Kerr 849d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 850d831f960SJeremy Kerr } 851