xref: /openbmc/obmc-console/console-server.c (revision fdf1a710)
1 /**
2  * Console server process for OpenBMC
3  *
4  * Copyright © 2016 IBM Corporation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #define _GNU_SOURCE
20 
21 #include <assert.h>
22 #include <errno.h>
23 #include <signal.h>
24 #include <stdint.h>
25 #include <stdbool.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <fcntl.h>
29 #include <unistd.h>
30 #include <err.h>
31 #include <string.h>
32 #include <getopt.h>
33 #include <limits.h>
34 #include <time.h>
35 #include <termios.h>
36 
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <poll.h>
40 
41 #include "console-server.h"
42 
43 #define DBUS_ERR "org.openbmc.error"
44 #define DBUS_NAME "xyz.openbmc_project.console"
45 #define OBJ_NAME "/xyz/openbmc_project/console"
46 
47 struct console {
48 	const char	*tty_kname;
49 	char		*tty_sysfs_devnode;
50 	char		*tty_dev;
51 	int		tty_sirq;
52 	int		tty_lpc_addr;
53 	speed_t		tty_baud;
54 	int		tty_fd;
55 
56 	struct ringbuffer	*rb;
57 
58 	struct handler	**handlers;
59 	int		n_handlers;
60 
61 	struct poller	**pollers;
62 	int		n_pollers;
63 
64 	struct pollfd	*pollfds;
65 	struct sd_bus	*bus;
66 };
67 
68 struct poller {
69 	struct handler	*handler;
70 	void		*data;
71 	poller_event_fn_t	event_fn;
72 	poller_timeout_fn_t	timeout_fn;
73 	struct timeval	timeout;
74 	bool		remove;
75 };
76 
77 /* we have two extra entry in the pollfds array for the VUART tty */
78 enum internal_pollfds {
79 	POLLFD_HOSTTTY = 0,
80 	POLLFD_DBUS = 1,
81 	MAX_INTERNAL_POLLFD = 2,
82 };
83 
84 /* size of the shared backlog ringbuffer */
85 const size_t buffer_size = 128 * 1024;
86 
87 /* state shared with the signal handler */
88 static bool sigint;
89 
90 static void usage(const char *progname)
91 {
92 	fprintf(stderr,
93 "usage: %s [options] <DEVICE>\n"
94 "\n"
95 "Options:\n"
96 "  --config <FILE>  Use FILE for configuration\n"
97 "",
98 		progname);
99 }
100 
101 /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */
102 static int tty_find_device(struct console *console)
103 {
104 	char *tty_class_device_link;
105 	char *tty_device_tty_dir;
106 	char *tty_device_reldir;
107 	char *tty_path_input;
108 	char *tty_path_input_real;
109 	char *tty_kname_real;
110 	int rc;
111 
112 	tty_class_device_link = NULL;
113 	tty_device_tty_dir = NULL;
114 	tty_device_reldir = NULL;
115 	tty_path_input = NULL;
116 	tty_path_input_real = NULL;
117 	tty_kname_real = NULL;
118 
119 	/* udev may rename the tty name with a symbol link, try to resolve */
120 	rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname);
121 	if (rc < 0)
122 		return -1;
123 
124 	tty_path_input_real = realpath(tty_path_input, NULL);
125 	if (!tty_path_input_real) {
126 		warn("Can't find realpath for /dev/%s", console->tty_kname);
127 		goto out_free;
128 	}
129 
130 	tty_kname_real = basename(tty_path_input_real);
131 	if (!tty_kname_real) {
132 		warn("Can't find real name for /dev/%s", console->tty_kname);
133 		goto out_free;
134 	}
135 
136 	rc = asprintf(&tty_class_device_link,
137 			"/sys/class/tty/%s", tty_kname_real);
138 	if (rc < 0)
139 		goto out_free;
140 
141 	tty_device_tty_dir = realpath(tty_class_device_link, NULL);
142 	if (!tty_device_tty_dir) {
143 		warn("Can't query sysfs for device %s", tty_kname_real);
144 		goto out_free;
145 	}
146 
147 	rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir);
148 	if (rc < 0)
149 		goto out_free;
150 
151 	console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL);
152 	if (!console->tty_sysfs_devnode)
153 		warn("Can't find parent device for %s", tty_kname_real);
154 
155 	rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real);
156 	if (rc < 0)
157 		goto out_free;
158 
159 	rc = 0;
160 
161 out_free:
162 	free(tty_class_device_link);
163 	free(tty_device_tty_dir);
164 	free(tty_device_reldir);
165 	free(tty_path_input);
166 	free(tty_path_input_real);
167 	return rc;
168 }
169 
170 static int tty_set_sysfs_attr(struct console *console, const char *name,
171 		int value)
172 {
173 	char *path;
174 	FILE *fp;
175 	int rc;
176 
177 	rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name);
178 	if (rc < 0)
179 		return -1;
180 
181 	fp = fopen(path, "w");
182 	if (!fp) {
183 		warn("Can't access attribute %s on device %s",
184 				name, console->tty_kname);
185 		rc = -1;
186 		goto out_free;
187 	}
188 	setvbuf(fp, NULL, _IONBF, 0);
189 
190 	rc = fprintf(fp, "0x%x", value);
191 	if (rc < 0)
192 		warn("Error writing to %s attribute of device %s",
193 				name, console->tty_kname);
194 	fclose(fp);
195 
196 
197 
198 out_free:
199 	free(path);
200 	return rc;
201 }
202 
203 /**
204  * Set termios attributes on the console tty.
205  */
206 static void tty_init_termios(struct console *console)
207 {
208 	struct termios termios;
209 	int rc;
210 
211 	rc = tcgetattr(console->tty_fd, &termios);
212 	if (rc) {
213 		warn("Can't read tty termios");
214 		return;
215 	}
216 
217 	if (console->tty_baud) {
218 		if (cfsetspeed(&termios, console->tty_baud) < 0)
219 			warn("Couldn't set speeds for %s", console->tty_kname);
220 	}
221 
222 	/* Set console to raw mode: we don't want any processing to occur on
223 	 * the underlying terminal input/output.
224 	 */
225 	cfmakeraw(&termios);
226 
227 	rc = tcsetattr(console->tty_fd, TCSANOW, &termios);
228 	if (rc)
229 		warn("Can't set terminal options for %s", console->tty_kname);
230 }
231 
232 
233 static void tty_change_baudrate(struct console *console)
234 {
235 	struct handler *handler;
236 	int i, rc;
237 
238 	tty_init_termios(console);
239 
240 	for (i = 0; i < console->n_handlers; i++) {
241 		handler = console->handlers[i];
242 		if (!handler->baudrate)
243 			continue;
244 
245 		rc = handler->baudrate(handler, console->tty_baud);
246 		if (rc)
247 			warnx("Can't set terminal baudrate for handler %s",
248 			     handler->name);
249 	}
250 }
251 
252 /**
253  * Open and initialise the serial device
254  */
255 static int tty_init_io(struct console *console)
256 {
257 	if (console->tty_sirq)
258 		tty_set_sysfs_attr(console, "sirq", console->tty_sirq);
259 	if (console->tty_lpc_addr)
260 		tty_set_sysfs_attr(console, "lpc_address",
261 				console->tty_lpc_addr);
262 
263 	console->tty_fd = open(console->tty_dev, O_RDWR);
264 	if (console->tty_fd <= 0) {
265 		warn("Can't open tty %s", console->tty_dev);
266 		return -1;
267 	}
268 
269 	/* Disable character delay. We may want to later enable this when
270 	 * we detect larger amounts of data
271 	 */
272 	fcntl(console->tty_fd, F_SETFL, FNDELAY);
273 
274 	tty_init_termios(console);
275 
276 	console->pollfds[console->n_pollers].fd = console->tty_fd;
277 	console->pollfds[console->n_pollers].events = POLLIN;
278 
279 	return 0;
280 }
281 
282 static int tty_init(struct console *console, struct config *config)
283 {
284 	const char *val;
285 	char *endp;
286 	int rc;
287 
288 	val = config_get_value(config, "lpc-address");
289 	if (val) {
290 		console->tty_lpc_addr = strtoul(val, &endp, 0);
291 		if (endp == optarg) {
292 			warn("Invalid LPC address: '%s'", val);
293 			return -1;
294 		}
295 	}
296 
297 	val = config_get_value(config, "sirq");
298 	if (val) {
299 		console->tty_sirq = strtoul(val, &endp, 0);
300 		if (endp == optarg)
301 			warn("Invalid sirq: '%s'", val);
302 	}
303 
304 	val = config_get_value(config, "baud");
305 	if (val) {
306 		if (config_parse_baud(&console->tty_baud, val))
307 			warnx("Invalid baud rate: '%s'", val);
308 	}
309 
310 	if (!console->tty_kname) {
311 		warnx("Error: No TTY device specified");
312 		return -1;
313 	}
314 
315 	rc = tty_find_device(console);
316 	if (rc)
317 		return rc;
318 
319 	rc = tty_init_io(console);
320 	return rc;
321 }
322 
323 
324 int console_data_out(struct console *console, const uint8_t *data, size_t len)
325 {
326 	return write_buf_to_fd(console->tty_fd, data, len);
327 }
328 
329 static int method_set_baud_rate(sd_bus_message *msg, void *userdata,
330 			 sd_bus_error *err)
331 {
332 	struct console *console = userdata;
333 	uint32_t baudrate;
334 	speed_t speed;
335 	int r;
336 
337 	if (!console) {
338 		sd_bus_error_set_const(err, DBUS_ERR, "Internal error");
339 		return sd_bus_reply_method_return(msg, "x", 0);
340 	}
341 
342 	r = sd_bus_message_read(msg, "u", &baudrate);
343 	if (r < 0) {
344 		sd_bus_error_set_const(err, DBUS_ERR, "Bad message");
345 		return sd_bus_reply_method_return(msg, "x", -EINVAL);
346 	}
347 
348 	speed = parse_int_to_baud(baudrate);
349 	if (!speed) {
350 		warnx("Invalid baud rate: '%u'", baudrate);
351 		return sd_bus_reply_method_return(msg, "x", -EINVAL);
352 	}
353 
354 	console->tty_baud = speed;
355 	tty_change_baudrate(console);
356 
357 	return sd_bus_reply_method_return(msg, "x", r);
358 }
359 
360 static int get_handler(sd_bus *bus, const char *path, const char *interface,
361 		       const char *property, sd_bus_message *reply, void *userdata,
362 		       sd_bus_error *error) {
363 	struct console *console = userdata;
364 	uint32_t baudrate;
365 	int r;
366 
367 	baudrate = parse_baud_to_int(console->tty_baud);
368 	if (!baudrate)
369 		warnx("Invalid baud rate: '%d'", console->tty_baud);
370 
371 	r = sd_bus_message_append(reply, "u", baudrate);
372 
373 	return r;
374 }
375 
376 static const sd_bus_vtable console_vtable[] = {
377 	SD_BUS_VTABLE_START(0),
378 	SD_BUS_METHOD("setBaudRate", "u", "x", method_set_baud_rate,
379 		      SD_BUS_VTABLE_UNPRIVILEGED),
380 	SD_BUS_PROPERTY("baudrate", "u", get_handler, 0, 0),
381 	SD_BUS_VTABLE_END,};
382 
383 static void dbus_init(struct console *console, struct config *config)
384 {
385 	int dbus_poller = 0;
386 	int fd, r;
387 
388 	if (!console) {
389 		warnx("Couldn't get valid console");
390 		return;
391 	}
392 
393 	r = sd_bus_default_system(&console->bus);
394 	if (r < 0) {
395 		warnx("Failed to connect to system bus: %s", strerror(-r));
396 		return;
397 	}
398 
399 	r = sd_bus_add_object_vtable(console->bus, NULL, OBJ_NAME, DBUS_NAME,
400 				     console_vtable, console);
401 	if (r < 0) {
402 		warnx("Failed to issue method call: %s", strerror(-r));
403 		return;
404 	}
405 
406 	r = sd_bus_request_name(console->bus, DBUS_NAME, SD_BUS_NAME_ALLOW_REPLACEMENT
407 				|SD_BUS_NAME_REPLACE_EXISTING);
408 	if (r < 0) {
409 		warnx("Failed to acquire service name: %s", strerror(-r));
410 		return;
411 	}
412 
413 	fd = sd_bus_get_fd(console->bus);
414 	if (fd < 0) {
415 		warnx("Couldn't get the bus file descriptor");
416 		return;
417 	}
418 
419 	dbus_poller = POLLFD_DBUS;
420 
421 	console->pollfds[dbus_poller].fd = fd;
422 	console->pollfds[dbus_poller].events = POLLIN;
423 }
424 
425 static void handlers_init(struct console *console, struct config *config)
426 {
427 	extern struct handler *__start_handlers, *__stop_handlers;
428 	struct handler *handler;
429 	int i, rc;
430 
431 	console->n_handlers = &__stop_handlers - &__start_handlers;
432 	console->handlers = &__start_handlers;
433 
434 	printf("%d handler%s\n", console->n_handlers,
435 			console->n_handlers == 1 ? "" : "s");
436 
437 	for (i = 0; i < console->n_handlers; i++) {
438 		handler = console->handlers[i];
439 
440 		rc = 0;
441 		if (handler->init)
442 			rc = handler->init(handler, console, config);
443 
444 		handler->active = rc == 0;
445 
446 		printf("  %s [%sactive]\n", handler->name,
447 				handler->active ? "" : "in");
448 	}
449 }
450 
451 static void handlers_fini(struct console *console)
452 {
453 	struct handler *handler;
454 	int i;
455 
456 	for (i = 0; i < console->n_handlers; i++) {
457 		handler = console->handlers[i];
458 		if (handler->fini && handler->active)
459 			handler->fini(handler);
460 	}
461 }
462 
463 static int get_current_time(struct timeval *tv)
464 {
465 	struct timespec t;
466 	int rc;
467 
468 	/*
469 	 * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to
470 	 * local time changes. However, a struct timeval is more
471 	 * convenient for calculations, so convert to that.
472 	 */
473 	rc = clock_gettime(CLOCK_MONOTONIC, &t);
474 	if (rc)
475 		return rc;
476 
477 	tv->tv_sec = t.tv_sec;
478 	tv->tv_usec = t.tv_nsec / 1000;
479 
480 	return 0;
481 }
482 
483 struct ringbuffer_consumer *console_ringbuffer_consumer_register(
484 		struct console *console,
485 		ringbuffer_poll_fn_t poll_fn, void *data)
486 {
487 	return ringbuffer_consumer_register(console->rb, poll_fn, data);
488 }
489 
490 struct poller *console_poller_register(struct console *console,
491 		struct handler *handler, poller_event_fn_t poller_fn,
492 		poller_timeout_fn_t timeout_fn, int fd,
493 		int events, void *data)
494 {
495 	struct poller *poller;
496 	int n;
497 
498 	poller = malloc(sizeof(*poller));
499 	poller->remove = false;
500 	poller->handler = handler;
501 	poller->event_fn = poller_fn;
502 	poller->timeout_fn = timeout_fn;
503 	poller->data = data;
504 
505 	/* add one to our pollers array */
506 	n = console->n_pollers++;
507 	console->pollers = realloc(console->pollers,
508 			sizeof(*console->pollers) * console->n_pollers);
509 
510 	console->pollers[n] = poller;
511 
512 	/* increase pollfds array too  */
513 	console->pollfds = realloc(console->pollfds,
514 			sizeof(*console->pollfds) *
515 				(MAX_INTERNAL_POLLFD + console->n_pollers));
516 
517 	/* shift the end pollfds up by one */
518 	memcpy(&console->pollfds[n+1],
519 		&console->pollfds[n],
520 		sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD);
521 
522 	console->pollfds[n].fd = fd;
523 	console->pollfds[n].events = events;
524 
525 	return poller;
526 }
527 
528 void console_poller_unregister(struct console *console,
529 		struct poller *poller)
530 {
531 	int i;
532 
533 	/* find the entry in our pollers array */
534 	for (i = 0; i < console->n_pollers; i++)
535 		if (console->pollers[i] == poller)
536 			break;
537 
538 	assert(i < console->n_pollers);
539 
540 	console->n_pollers--;
541 
542 	/* remove the item from the pollers array... */
543 	memmove(&console->pollers[i], &console->pollers[i+1],
544 			sizeof(*console->pollers)
545 				* (console->n_pollers - i));
546 
547 	console->pollers = realloc(console->pollers,
548 			sizeof(*console->pollers) * console->n_pollers);
549 
550 	/* ... and the pollfds array */
551 	memmove(&console->pollfds[i], &console->pollfds[i+1],
552 			sizeof(*console->pollfds) *
553 				(MAX_INTERNAL_POLLFD + console->n_pollers - i));
554 
555 	console->pollfds = realloc(console->pollfds,
556 			sizeof(*console->pollfds) *
557 				(MAX_INTERNAL_POLLFD + console->n_pollers));
558 
559 
560 	free(poller);
561 }
562 
563 void console_poller_set_events(struct console *console, struct poller *poller,
564 		int events)
565 {
566 	int i;
567 
568 	/* find the entry in our pollers array */
569 	for (i = 0; i < console->n_pollers; i++)
570 		if (console->pollers[i] == poller)
571 			break;
572 
573 	console->pollfds[i].events = events;
574 }
575 
576 void console_poller_set_timeout(struct console *console, struct poller *poller,
577 		const struct timeval *tv)
578 {
579 	struct timeval now;
580 	int rc;
581 
582 	rc = get_current_time(&now);
583 	if (rc)
584 		return;
585 
586 	timeradd(&now, tv, &poller->timeout);
587 }
588 
589 static int get_poll_timeout(struct console *console, struct timeval *cur_time)
590 {
591 	struct timeval *earliest, interval;
592 	struct poller *poller;
593 	int i;
594 
595 	earliest = NULL;
596 
597 	for (i = 0; i < console->n_pollers; i++) {
598 		poller = console->pollers[i];
599 
600 		if (poller->timeout_fn && timerisset(&poller->timeout) &&
601 		    (!earliest ||
602 		     (earliest && timercmp(&poller->timeout, earliest, <)))){
603 			// poller is buffering data and needs the poll
604 			// function to timeout.
605 			earliest = &poller->timeout;
606 		}
607 	}
608 
609 	if (earliest) {
610 		if (timercmp(earliest, cur_time, >)) {
611 			/* recalculate the timeout period, time period has
612 			 * not elapsed */
613 			timersub(earliest, cur_time, &interval);
614 			return ((interval.tv_sec * 1000) +
615 				(interval.tv_usec / 1000));
616 		} else {
617 			/* return from poll immediately */
618 			return 0;
619 		}
620 	} else {
621 		/* poll indefinitely */
622 		return -1;
623 	}
624 }
625 
626 static int call_pollers(struct console *console, struct timeval *cur_time)
627 {
628 	struct poller *poller;
629 	struct pollfd *pollfd;
630 	enum poller_ret prc;
631 	int i, rc;
632 
633 	rc = 0;
634 
635 	/*
636 	 * Process poll events by iterating through the pollers and pollfds
637 	 * in-step, calling any pollers that we've found revents for.
638 	 */
639 	for (i = 0; i < console->n_pollers; i++) {
640 		poller = console->pollers[i];
641 		pollfd = &console->pollfds[i];
642 		prc = POLLER_OK;
643 
644 		/* process pending events... */
645 		if (pollfd->revents) {
646 			prc = poller->event_fn(poller->handler, pollfd->revents,
647 					poller->data);
648 			if (prc == POLLER_EXIT)
649 				rc = -1;
650 			else if (prc == POLLER_REMOVE)
651 				poller->remove = true;
652 		}
653 
654 		if ((prc == POLLER_OK) && poller->timeout_fn &&
655 		    timerisset(&poller->timeout) &&
656 		    timercmp(&poller->timeout, cur_time, <=)) {
657 			/* One of the ringbuffer consumers is buffering the
658 			data stream. The amount of idle time the consumer
659 			desired has expired.  Process the buffered data for
660 			transmission. */
661 			timerclear(&poller->timeout);
662 			prc = poller->timeout_fn(poller->handler, poller->data);
663 			if (prc == POLLER_EXIT) {
664 				rc = -1;
665 			} else if (prc == POLLER_REMOVE) {
666 				poller->remove = true;
667 			}
668 		}
669 	}
670 
671 	/**
672 	 * Process deferred removals; restarting each time we unregister, as
673 	 * the array will have changed
674 	 */
675 	for (;;) {
676 		bool removed = false;
677 
678 		for (i = 0; i < console->n_pollers; i++) {
679 			poller = console->pollers[i];
680 			if (poller->remove) {
681 				console_poller_unregister(console, poller);
682 				removed = true;
683 				break;
684 			}
685 		}
686 		if (!removed)
687 			break;
688 	}
689 
690 	return rc;
691 }
692 
693 static void sighandler(int signal)
694 {
695 	if (signal == SIGINT)
696 		sigint = true;
697 }
698 
699 int run_console(struct console *console)
700 {
701 	sighandler_t sighandler_save;
702 	struct timeval tv;
703 	int rc, timeout;
704 
705 	sighandler_save = signal(SIGINT, sighandler);
706 
707 	rc = 0;
708 
709 	for (;;) {
710 		uint8_t buf[4096];
711 
712 		BUILD_ASSERT(sizeof(buf) <= buffer_size);
713 
714 		if (sigint) {
715 			fprintf(stderr, "Received interrupt, exiting\n");
716 			break;
717 		}
718 
719 		rc = get_current_time(&tv);
720 		if (rc) {
721 			warn("Failed to read current time");
722 			break;
723 		}
724 
725 		timeout = get_poll_timeout(console, &tv);
726 
727 		rc = poll(console->pollfds,
728 				console->n_pollers + MAX_INTERNAL_POLLFD,
729 				timeout);
730 
731 		if (rc < 0) {
732 			if (errno == EINTR) {
733 				continue;
734 			} else {
735 				warn("poll error");
736 				break;
737 			}
738 		}
739 
740 		/* process internal fd first */
741 		if (console->pollfds[console->n_pollers].revents) {
742 			rc = read(console->tty_fd, buf, sizeof(buf));
743 			if (rc <= 0) {
744 				warn("Error reading from tty device");
745 				rc = -1;
746 				break;
747 			}
748 			rc = ringbuffer_queue(console->rb, buf, rc);
749 			if (rc)
750 				break;
751 		}
752 
753 		if (console->pollfds[console->n_pollers + 1].revents) {
754 			sd_bus_process(console->bus, NULL);
755 		}
756 
757 		/* ... and then the pollers */
758 		rc = call_pollers(console, &tv);
759 		if (rc)
760 			break;
761 	}
762 
763 	signal(SIGINT, sighandler_save);
764 	sd_bus_unref(console->bus);
765 
766 	return rc ? -1 : 0;
767 }
768 static const struct option options[] = {
769 	{ "config",	required_argument,	0, 'c'},
770 	{ 0,  0, 0, 0},
771 };
772 
773 int main(int argc, char **argv)
774 {
775 	const char *config_filename = NULL;
776 	const char *config_tty_kname = NULL;
777 	struct console *console;
778 	struct config *config;
779 	int rc;
780 
781 	rc = -1;
782 
783 	for (;;) {
784 		int c, idx;
785 
786 		c = getopt_long(argc, argv, "c:", options, &idx);
787 		if (c == -1)
788 			break;
789 
790 		switch (c) {
791 		case 'c':
792 			config_filename = optarg;
793 			break;
794 		case 'h':
795 		case '?':
796 			usage(argv[0]);
797 			return EXIT_SUCCESS;
798 		}
799 	}
800 
801 	if (optind < argc)
802 		config_tty_kname = argv[optind];
803 
804 	console = malloc(sizeof(struct console));
805 	memset(console, 0, sizeof(*console));
806 	console->pollfds = calloc(MAX_INTERNAL_POLLFD,
807 			sizeof(*console->pollfds));
808 	console->rb = ringbuffer_init(buffer_size);
809 
810 	config = config_init(config_filename);
811 	if (!config) {
812 		warnx("Can't read configuration, exiting.");
813 		goto out_free;
814 	}
815 
816 	if (!config_tty_kname)
817 		config_tty_kname = config_get_value(config, "upstream-tty");
818 
819 	if (!config_tty_kname) {
820 		warnx("No TTY device specified");
821 		usage(argv[0]);
822 		return EXIT_FAILURE;
823 	}
824 
825 	console->tty_kname = config_tty_kname;
826 
827 	rc = tty_init(console, config);
828 	if (rc)
829 		goto out_config_fini;
830 
831 	dbus_init(console, config);
832 
833 	handlers_init(console, config);
834 
835 	rc = run_console(console);
836 
837 	handlers_fini(console);
838 
839 out_config_fini:
840 	config_fini(config);
841 
842 out_free:
843 	free(console->pollers);
844 	free(console->pollfds);
845 	free(console->tty_sysfs_devnode);
846 	free(console->tty_dev);
847 	free(console);
848 
849 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
850 }
851