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> 34*1cecc5deSJohnathan Mantey #include <time.h> 3554e9569dSJeremy Kerr #include <termios.h> 36d831f960SJeremy Kerr 37d831f960SJeremy Kerr #include <sys/types.h> 38*1cecc5deSJohnathan 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; 71*1cecc5deSJohnathan Mantey poller_event_fn_t event_fn; 72*1cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn; 73*1cecc5deSJohnathan 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 463*1cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv) 464*1cecc5deSJohnathan Mantey { 465*1cecc5deSJohnathan Mantey struct timespec t; 466*1cecc5deSJohnathan Mantey int rc; 467*1cecc5deSJohnathan Mantey 468*1cecc5deSJohnathan Mantey /* 469*1cecc5deSJohnathan Mantey * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to 470*1cecc5deSJohnathan Mantey * local time changes. However, a struct timeval is more 471*1cecc5deSJohnathan Mantey * convenient for calculations, so convert to that. 472*1cecc5deSJohnathan Mantey */ 473*1cecc5deSJohnathan Mantey rc = clock_gettime(CLOCK_MONOTONIC, &t); 474*1cecc5deSJohnathan Mantey if (rc) 475*1cecc5deSJohnathan Mantey return rc; 476*1cecc5deSJohnathan Mantey 477*1cecc5deSJohnathan Mantey tv->tv_sec = t.tv_sec; 478*1cecc5deSJohnathan Mantey tv->tv_usec = t.tv_nsec / 1000; 479*1cecc5deSJohnathan Mantey 480*1cecc5deSJohnathan Mantey return 0; 481*1cecc5deSJohnathan Mantey } 482*1cecc5deSJohnathan 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, 491*1cecc5deSJohnathan Mantey struct handler *handler, poller_event_fn_t poller_fn, 492*1cecc5deSJohnathan Mantey poller_timeout_fn_t timeout_fn, int fd, 493*1cecc5deSJohnathan 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; 501*1cecc5deSJohnathan Mantey poller->event_fn = poller_fn; 502*1cecc5deSJohnathan 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 576*1cecc5deSJohnathan Mantey void console_poller_set_timeout(struct console *console, struct poller *poller, 577*1cecc5deSJohnathan Mantey const struct timeval *tv) 578*1cecc5deSJohnathan Mantey { 579*1cecc5deSJohnathan Mantey struct timeval now; 580*1cecc5deSJohnathan Mantey int rc; 581*1cecc5deSJohnathan Mantey 582*1cecc5deSJohnathan Mantey rc = get_current_time(&now); 583*1cecc5deSJohnathan Mantey if (rc) 584*1cecc5deSJohnathan Mantey return; 585*1cecc5deSJohnathan Mantey 586*1cecc5deSJohnathan Mantey timeradd(&now, tv, &poller->timeout); 587*1cecc5deSJohnathan Mantey } 588*1cecc5deSJohnathan Mantey 589*1cecc5deSJohnathan Mantey static int get_poll_timeout(struct console *console, struct timeval *cur_time) 590*1cecc5deSJohnathan Mantey { 591*1cecc5deSJohnathan Mantey struct timeval *earliest, interval; 592*1cecc5deSJohnathan Mantey struct poller *poller; 593*1cecc5deSJohnathan Mantey int i; 594*1cecc5deSJohnathan Mantey 595*1cecc5deSJohnathan Mantey earliest = NULL; 596*1cecc5deSJohnathan Mantey 597*1cecc5deSJohnathan Mantey for (i = 0; i < console->n_pollers; i++) { 598*1cecc5deSJohnathan Mantey poller = console->pollers[i]; 599*1cecc5deSJohnathan Mantey 600*1cecc5deSJohnathan Mantey if (poller->timeout_fn && timerisset(&poller->timeout) && 601*1cecc5deSJohnathan Mantey (!earliest || 602*1cecc5deSJohnathan Mantey (earliest && timercmp(&poller->timeout, earliest, <)))){ 603*1cecc5deSJohnathan Mantey // poller is buffering data and needs the poll 604*1cecc5deSJohnathan Mantey // function to timeout. 605*1cecc5deSJohnathan Mantey earliest = &poller->timeout; 606*1cecc5deSJohnathan Mantey } 607*1cecc5deSJohnathan Mantey } 608*1cecc5deSJohnathan Mantey 609*1cecc5deSJohnathan Mantey if (earliest) { 610*1cecc5deSJohnathan Mantey if (timercmp(earliest, cur_time, >)) { 611*1cecc5deSJohnathan Mantey /* recalculate the timeout period, time period has 612*1cecc5deSJohnathan Mantey * not elapsed */ 613*1cecc5deSJohnathan Mantey timersub(earliest, cur_time, &interval); 614*1cecc5deSJohnathan Mantey return ((interval.tv_sec * 1000) + 615*1cecc5deSJohnathan Mantey (interval.tv_usec / 1000)); 616*1cecc5deSJohnathan Mantey } else { 617*1cecc5deSJohnathan Mantey /* return from poll immediately */ 618*1cecc5deSJohnathan Mantey return 0; 619*1cecc5deSJohnathan Mantey } 620*1cecc5deSJohnathan Mantey } else { 621*1cecc5deSJohnathan Mantey /* poll indefinitely */ 622*1cecc5deSJohnathan Mantey return -1; 623*1cecc5deSJohnathan Mantey } 624*1cecc5deSJohnathan Mantey } 625*1cecc5deSJohnathan Mantey 626*1cecc5deSJohnathan 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]; 642*1cecc5deSJohnathan Mantey prc = POLLER_OK; 6431a0e03b4SJeremy Kerr 644*1cecc5deSJohnathan Mantey /* process pending events... */ 645*1cecc5deSJohnathan Mantey if (pollfd->revents) { 646*1cecc5deSJohnathan 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 654*1cecc5deSJohnathan Mantey if ((prc == POLLER_OK) && poller->timeout_fn && 655*1cecc5deSJohnathan Mantey timerisset(&poller->timeout) && 656*1cecc5deSJohnathan Mantey timercmp(&poller->timeout, cur_time, <=)) { 657*1cecc5deSJohnathan Mantey /* One of the ringbuffer consumers is buffering the 658*1cecc5deSJohnathan Mantey data stream. The amount of idle time the consumer 659*1cecc5deSJohnathan Mantey desired has expired. Process the buffered data for 660*1cecc5deSJohnathan Mantey transmission. */ 661*1cecc5deSJohnathan Mantey timerclear(&poller->timeout); 662*1cecc5deSJohnathan Mantey prc = poller->timeout_fn(poller->handler, poller->data); 663*1cecc5deSJohnathan Mantey if (prc == POLLER_EXIT) { 664*1cecc5deSJohnathan Mantey rc = -1; 665*1cecc5deSJohnathan Mantey } else if (prc == POLLER_REMOVE) { 666*1cecc5deSJohnathan Mantey poller->remove = true; 667*1cecc5deSJohnathan Mantey } 668*1cecc5deSJohnathan Mantey } 669*1cecc5deSJohnathan Mantey } 670*1cecc5deSJohnathan 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; 702*1cecc5deSJohnathan Mantey struct timeval tv; 703*1cecc5deSJohnathan 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 719*1cecc5deSJohnathan Mantey rc = get_current_time(&tv); 720*1cecc5deSJohnathan Mantey if (rc) { 721*1cecc5deSJohnathan Mantey warn("Failed to read current time"); 722*1cecc5deSJohnathan Mantey break; 723*1cecc5deSJohnathan Mantey } 724*1cecc5deSJohnathan Mantey 725*1cecc5deSJohnathan Mantey timeout = get_poll_timeout(console, &tv); 726*1cecc5deSJohnathan Mantey 727329a35f5SJeremy Kerr rc = poll(console->pollfds, 728*1cecc5deSJohnathan Mantey console->n_pollers + MAX_INTERNAL_POLLFD, 729*1cecc5deSJohnathan Mantey timeout); 730*1cecc5deSJohnathan 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 */ 758*1cecc5deSJohnathan 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 8016221ce94SVishwanatha Subbanna if (optind >= argc) { 8026221ce94SVishwanatha Subbanna warnx("Required argument <DEVICE> missing"); 8036221ce94SVishwanatha Subbanna usage(argv[0]); 8046221ce94SVishwanatha Subbanna return EXIT_FAILURE; 8056221ce94SVishwanatha Subbanna } 8066221ce94SVishwanatha Subbanna 8076221ce94SVishwanatha Subbanna config_tty_kname = argv[optind]; 8086221ce94SVishwanatha Subbanna 809d66195c1SJeremy Kerr console = malloc(sizeof(struct console)); 810d66195c1SJeremy Kerr memset(console, 0, sizeof(*console)); 811f9c8f6caSCheng C Yang console->pollfds = calloc(MAX_INTERNAL_POLLFD, 812329a35f5SJeremy Kerr sizeof(*console->pollfds)); 813f733c85aSJeremy Kerr console->rb = ringbuffer_init(buffer_size); 814329a35f5SJeremy Kerr 815d66195c1SJeremy Kerr config = config_init(config_filename); 816d66195c1SJeremy Kerr if (!config) { 817d66195c1SJeremy Kerr warnx("Can't read configuration, exiting."); 818d66195c1SJeremy Kerr goto out_free; 819d831f960SJeremy Kerr } 820d831f960SJeremy Kerr 8216221ce94SVishwanatha Subbanna console->tty_kname = config_tty_kname; 8226221ce94SVishwanatha Subbanna 823d66195c1SJeremy Kerr rc = tty_init(console, config); 82417217845SJeremy Kerr if (rc) 825d66195c1SJeremy Kerr goto out_config_fini; 826d831f960SJeremy Kerr 827f9c8f6caSCheng C Yang dbus_init(console, config); 828f9c8f6caSCheng C Yang 829d47963e5SJeremy Kerr handlers_init(console, config); 830d831f960SJeremy Kerr 8311a0e03b4SJeremy Kerr rc = run_console(console); 832d831f960SJeremy Kerr 8331a0e03b4SJeremy Kerr handlers_fini(console); 834d831f960SJeremy Kerr 835d66195c1SJeremy Kerr out_config_fini: 836d66195c1SJeremy Kerr config_fini(config); 837d66195c1SJeremy Kerr 838957818b4SJeremy Kerr out_free: 83989ea8198SJeremy Kerr free(console->pollers); 84089ea8198SJeremy Kerr free(console->pollfds); 8411a0e03b4SJeremy Kerr free(console->tty_sysfs_devnode); 8421a0e03b4SJeremy Kerr free(console->tty_dev); 8431a0e03b4SJeremy Kerr free(console); 844d831f960SJeremy Kerr 845d831f960SJeremy Kerr return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; 846d831f960SJeremy Kerr } 847