xref: /openbmc/obmc-console/console-server.c (revision d3cb9c224bc63c61d0dabd529d3074278496a39a)
1d831f960SJeremy Kerr /**
2d831f960SJeremy Kerr  * Console server process for OpenBMC
3d831f960SJeremy Kerr  *
49326d779SJeremy Kerr  * Copyright © 2016 IBM Corporation
59326d779SJeremy Kerr  *
69326d779SJeremy Kerr  * Licensed under the Apache License, Version 2.0 (the "License");
79326d779SJeremy Kerr  * you may not use this file except in compliance with the License.
89326d779SJeremy Kerr  * You may obtain a copy of the License at
99326d779SJeremy Kerr  *
109326d779SJeremy Kerr  *     http://www.apache.org/licenses/LICENSE-2.0
119326d779SJeremy Kerr  *
129326d779SJeremy Kerr  * Unless required by applicable law or agreed to in writing, software
139326d779SJeremy Kerr  * distributed under the License is distributed on an "AS IS" BASIS,
149326d779SJeremy Kerr  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159326d779SJeremy Kerr  * See the License for the specific language governing permissions and
169326d779SJeremy Kerr  * limitations under the License.
17d831f960SJeremy Kerr  */
18d831f960SJeremy Kerr 
19329a35f5SJeremy Kerr #include <assert.h>
20769cee1aSJeremy Kerr #include <errno.h>
21769cee1aSJeremy Kerr #include <signal.h>
22d831f960SJeremy Kerr #include <stdint.h>
23d831f960SJeremy Kerr #include <stdbool.h>
24d831f960SJeremy Kerr #include <stdlib.h>
25d831f960SJeremy Kerr #include <stdio.h>
26d831f960SJeremy Kerr #include <fcntl.h>
27d831f960SJeremy Kerr #include <unistd.h>
28d831f960SJeremy Kerr #include <err.h>
29d831f960SJeremy Kerr #include <string.h>
30d831f960SJeremy Kerr #include <getopt.h>
3117217845SJeremy Kerr #include <limits.h>
321cecc5deSJohnathan Mantey #include <time.h>
3354e9569dSJeremy Kerr #include <termios.h>
34d831f960SJeremy Kerr 
35d831f960SJeremy Kerr #include <sys/types.h>
361cecc5deSJohnathan Mantey #include <sys/time.h>
37b14ca19cSNinad Palsule #include <sys/socket.h>
3887e344cdSJoel Stanley #include <poll.h>
39d831f960SJeremy Kerr 
401a0e03b4SJeremy Kerr #include "console-server.h"
41d831f960SJeremy Kerr 
42f733c85aSJeremy Kerr /* size of the shared backlog ringbuffer */
435db8c792SAndrew Jeffery const size_t buffer_size = 128ul * 1024ul;
44f733c85aSJeremy Kerr 
45769cee1aSJeremy Kerr /* state shared with the signal handler */
46769cee1aSJeremy Kerr static bool sigint;
47329a35f5SJeremy Kerr 
48d831f960SJeremy Kerr static void usage(const char *progname)
49d831f960SJeremy Kerr {
50d831f960SJeremy Kerr 	fprintf(stderr,
516221ce94SVishwanatha Subbanna 		"usage: %s [options] <DEVICE>\n"
52d831f960SJeremy Kerr 		"\n"
53d831f960SJeremy Kerr 		"Options:\n"
54d66195c1SJeremy Kerr 		"  --config <FILE>  Use FILE for configuration\n"
55d831f960SJeremy Kerr 		"",
56d831f960SJeremy Kerr 		progname);
57d831f960SJeremy Kerr }
58d831f960SJeremy Kerr 
5917217845SJeremy Kerr /* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */
601a0e03b4SJeremy Kerr static int tty_find_device(struct console *console)
6117217845SJeremy Kerr {
62*d3cb9c22SAndrew Jeffery 	char *tty_class_device_link = NULL;
63*d3cb9c22SAndrew Jeffery 	char *tty_path_input_real = NULL;
64*d3cb9c22SAndrew Jeffery 	char *tty_device_tty_dir = NULL;
65*d3cb9c22SAndrew Jeffery 	char *tty_device_reldir = NULL;
66*d3cb9c22SAndrew Jeffery 	char *tty_path_input = NULL;
67*d3cb9c22SAndrew Jeffery 	char *tty_kname_real = NULL;
6817217845SJeremy Kerr 	int rc;
6917217845SJeremy Kerr 
7045ad7676SYi Li 	/* udev may rename the tty name with a symbol link, try to resolve */
7145ad7676SYi Li 	rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname);
722834c5b1SAndrew Jeffery 	if (rc < 0) {
7317217845SJeremy Kerr 		return -1;
742834c5b1SAndrew Jeffery 	}
7517217845SJeremy Kerr 
7645ad7676SYi Li 	tty_path_input_real = realpath(tty_path_input, NULL);
7745ad7676SYi Li 	if (!tty_path_input_real) {
7845ad7676SYi Li 		warn("Can't find realpath for /dev/%s", console->tty_kname);
7915792aa7SAndrew Jeffery 		rc = -1;
8045ad7676SYi Li 		goto out_free;
8145ad7676SYi Li 	}
8245ad7676SYi Li 
8345ad7676SYi Li 	tty_kname_real = basename(tty_path_input_real);
8445ad7676SYi Li 	if (!tty_kname_real) {
8545ad7676SYi Li 		warn("Can't find real name for /dev/%s", console->tty_kname);
8615792aa7SAndrew Jeffery 		rc = -1;
8745ad7676SYi Li 		goto out_free;
8845ad7676SYi Li 	}
8945ad7676SYi Li 
90a72711afSAndrew Jeffery 	rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s",
91a72711afSAndrew Jeffery 		      tty_kname_real);
922834c5b1SAndrew Jeffery 	if (rc < 0) {
9345ad7676SYi Li 		goto out_free;
942834c5b1SAndrew Jeffery 	}
9545ad7676SYi Li 
9617217845SJeremy Kerr 	tty_device_tty_dir = realpath(tty_class_device_link, NULL);
9745ad7676SYi Li 	if (!tty_device_tty_dir) {
9845ad7676SYi Li 		warn("Can't query sysfs for device %s", tty_kname_real);
9915792aa7SAndrew Jeffery 		rc = -1;
10017217845SJeremy Kerr 		goto out_free;
10117217845SJeremy Kerr 	}
10217217845SJeremy Kerr 
10317217845SJeremy Kerr 	rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir);
1042834c5b1SAndrew Jeffery 	if (rc < 0) {
10517217845SJeremy Kerr 		goto out_free;
1062834c5b1SAndrew Jeffery 	}
10717217845SJeremy Kerr 
1081a0e03b4SJeremy Kerr 	console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL);
1092834c5b1SAndrew Jeffery 	if (!console->tty_sysfs_devnode) {
11045ad7676SYi Li 		warn("Can't find parent device for %s", tty_kname_real);
1112834c5b1SAndrew Jeffery 	}
11217217845SJeremy Kerr 
11345ad7676SYi Li 	rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real);
1142834c5b1SAndrew Jeffery 	if (rc < 0) {
11517217845SJeremy Kerr 		goto out_free;
1162834c5b1SAndrew Jeffery 	}
11717217845SJeremy Kerr 
11817217845SJeremy Kerr 	rc = 0;
11917217845SJeremy Kerr 
12017217845SJeremy Kerr out_free:
12117217845SJeremy Kerr 	free(tty_class_device_link);
12217217845SJeremy Kerr 	free(tty_device_tty_dir);
12317217845SJeremy Kerr 	free(tty_device_reldir);
12445ad7676SYi Li 	free(tty_path_input);
12545ad7676SYi Li 	free(tty_path_input_real);
12617217845SJeremy Kerr 	return rc;
12717217845SJeremy Kerr }
12817217845SJeremy Kerr 
1291a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name,
130957818b4SJeremy Kerr 			      int value)
131957818b4SJeremy Kerr {
132957818b4SJeremy Kerr 	char *path;
133957818b4SJeremy Kerr 	FILE *fp;
134957818b4SJeremy Kerr 	int rc;
135957818b4SJeremy Kerr 
1361a0e03b4SJeremy Kerr 	rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name);
1372834c5b1SAndrew Jeffery 	if (rc < 0) {
138957818b4SJeremy Kerr 		return -1;
1392834c5b1SAndrew Jeffery 	}
140957818b4SJeremy Kerr 
141957818b4SJeremy Kerr 	fp = fopen(path, "w");
142957818b4SJeremy Kerr 	if (!fp) {
143a72711afSAndrew Jeffery 		warn("Can't access attribute %s on device %s", name,
144a72711afSAndrew Jeffery 		     console->tty_kname);
145957818b4SJeremy Kerr 		rc = -1;
146957818b4SJeremy Kerr 		goto out_free;
147957818b4SJeremy Kerr 	}
148957818b4SJeremy Kerr 	setvbuf(fp, NULL, _IONBF, 0);
149957818b4SJeremy Kerr 
150957818b4SJeremy Kerr 	rc = fprintf(fp, "0x%x", value);
1512834c5b1SAndrew Jeffery 	if (rc < 0) {
152a72711afSAndrew Jeffery 		warn("Error writing to %s attribute of device %s", name,
153a72711afSAndrew Jeffery 		     console->tty_kname);
1542834c5b1SAndrew Jeffery 	}
155957818b4SJeremy Kerr 	fclose(fp);
156957818b4SJeremy Kerr 
157957818b4SJeremy Kerr out_free:
158957818b4SJeremy Kerr 	free(path);
159957818b4SJeremy Kerr 	return rc;
160957818b4SJeremy Kerr }
161957818b4SJeremy Kerr 
162d831f960SJeremy Kerr /**
163c7fbcd48SBenjamin Fair  * Set termios attributes on the console tty.
16454e9569dSJeremy Kerr  */
165e258e51fSNinad Palsule void tty_init_termios(struct console *console)
16654e9569dSJeremy Kerr {
16754e9569dSJeremy Kerr 	struct termios termios;
16854e9569dSJeremy Kerr 	int rc;
16954e9569dSJeremy Kerr 
17054e9569dSJeremy Kerr 	rc = tcgetattr(console->tty_fd, &termios);
17154e9569dSJeremy Kerr 	if (rc) {
17254e9569dSJeremy Kerr 		warn("Can't read tty termios");
17354e9569dSJeremy Kerr 		return;
17454e9569dSJeremy Kerr 	}
17554e9569dSJeremy Kerr 
176c7fbcd48SBenjamin Fair 	if (console->tty_baud) {
1772834c5b1SAndrew Jeffery 		if (cfsetspeed(&termios, console->tty_baud) < 0) {
178c7fbcd48SBenjamin Fair 			warn("Couldn't set speeds for %s", console->tty_kname);
179c7fbcd48SBenjamin Fair 		}
1802834c5b1SAndrew Jeffery 	}
181c7fbcd48SBenjamin Fair 
182c7fbcd48SBenjamin Fair 	/* Set console to raw mode: we don't want any processing to occur on
183c7fbcd48SBenjamin Fair 	 * the underlying terminal input/output.
184c7fbcd48SBenjamin Fair 	 */
18554e9569dSJeremy Kerr 	cfmakeraw(&termios);
186c7fbcd48SBenjamin Fair 
18754e9569dSJeremy Kerr 	rc = tcsetattr(console->tty_fd, TCSANOW, &termios);
1882834c5b1SAndrew Jeffery 	if (rc) {
189c7fbcd48SBenjamin Fair 		warn("Can't set terminal options for %s", console->tty_kname);
19054e9569dSJeremy Kerr 	}
1912834c5b1SAndrew Jeffery }
19254e9569dSJeremy Kerr 
19354e9569dSJeremy Kerr /**
194d831f960SJeremy Kerr  * Open and initialise the serial device
195d831f960SJeremy Kerr  */
1961a0e03b4SJeremy Kerr static int tty_init_io(struct console *console)
197d831f960SJeremy Kerr {
1982834c5b1SAndrew Jeffery 	if (console->tty_sirq) {
1991a0e03b4SJeremy Kerr 		tty_set_sysfs_attr(console, "sirq", console->tty_sirq);
2002834c5b1SAndrew Jeffery 	}
2012834c5b1SAndrew Jeffery 	if (console->tty_lpc_addr) {
2021a0e03b4SJeremy Kerr 		tty_set_sysfs_attr(console, "lpc_address",
2031a0e03b4SJeremy Kerr 				   console->tty_lpc_addr);
2042834c5b1SAndrew Jeffery 	}
205957818b4SJeremy Kerr 
2061a0e03b4SJeremy Kerr 	console->tty_fd = open(console->tty_dev, O_RDWR);
2071a0e03b4SJeremy Kerr 	if (console->tty_fd <= 0) {
2081a0e03b4SJeremy Kerr 		warn("Can't open tty %s", console->tty_dev);
209d831f960SJeremy Kerr 		return -1;
210d831f960SJeremy Kerr 	}
211d831f960SJeremy Kerr 
212d831f960SJeremy Kerr 	/* Disable character delay. We may want to later enable this when
213d831f960SJeremy Kerr 	 * we detect larger amounts of data
214d831f960SJeremy Kerr 	 */
2151a0e03b4SJeremy Kerr 	fcntl(console->tty_fd, F_SETFL, FNDELAY);
216d831f960SJeremy Kerr 
21754e9569dSJeremy Kerr 	tty_init_termios(console);
21854e9569dSJeremy Kerr 
219329a35f5SJeremy Kerr 	console->pollfds[console->n_pollers].fd = console->tty_fd;
220329a35f5SJeremy Kerr 	console->pollfds[console->n_pollers].events = POLLIN;
221329a35f5SJeremy Kerr 
222d831f960SJeremy Kerr 	return 0;
223d831f960SJeremy Kerr }
224d831f960SJeremy Kerr 
225d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config)
226d66195c1SJeremy Kerr {
227fd883a88SAndrew Jeffery 	unsigned long parsed;
228d66195c1SJeremy Kerr 	const char *val;
229d66195c1SJeremy Kerr 	char *endp;
230d66195c1SJeremy Kerr 	int rc;
231d66195c1SJeremy Kerr 
232d66195c1SJeremy Kerr 	val = config_get_value(config, "lpc-address");
233d66195c1SJeremy Kerr 	if (val) {
234fd883a88SAndrew Jeffery 		errno = 0;
235fd883a88SAndrew Jeffery 		parsed = strtoul(val, &endp, 0);
236fd883a88SAndrew Jeffery 		if (parsed == ULONG_MAX && errno == ERANGE) {
237fd883a88SAndrew Jeffery 			warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'",
238fd883a88SAndrew Jeffery 			     val);
239fd883a88SAndrew Jeffery 			return -1;
240fd883a88SAndrew Jeffery 		}
241fd883a88SAndrew Jeffery 
242fd883a88SAndrew Jeffery 		if (parsed > UINT16_MAX) {
243fd883a88SAndrew Jeffery 			warn("Invalid LPC address '%s'", val);
244fd883a88SAndrew Jeffery 			return -1;
245fd883a88SAndrew Jeffery 		}
246fd883a88SAndrew Jeffery 
247fd883a88SAndrew Jeffery 		console->tty_lpc_addr = (uint16_t)parsed;
248d66195c1SJeremy Kerr 		if (endp == optarg) {
249d66195c1SJeremy Kerr 			warn("Invalid LPC address: '%s'", val);
250d66195c1SJeremy Kerr 			return -1;
251d66195c1SJeremy Kerr 		}
252d66195c1SJeremy Kerr 	}
253d66195c1SJeremy Kerr 
254d66195c1SJeremy Kerr 	val = config_get_value(config, "sirq");
255d66195c1SJeremy Kerr 	if (val) {
256fd883a88SAndrew Jeffery 		errno = 0;
257fd883a88SAndrew Jeffery 		parsed = strtoul(val, &endp, 0);
258fd883a88SAndrew Jeffery 		if (parsed == ULONG_MAX && errno == ERANGE) {
259fd883a88SAndrew Jeffery 			warn("Cannot interpret 'sirq' value as an unsigned long: '%s'",
260fd883a88SAndrew Jeffery 			     val);
261fd883a88SAndrew Jeffery 		}
262fd883a88SAndrew Jeffery 
2632834c5b1SAndrew Jeffery 		if (parsed > 16) {
264fd883a88SAndrew Jeffery 			warn("Invalid LPC SERIRQ: '%s'", val);
2652834c5b1SAndrew Jeffery 		}
266fd883a88SAndrew Jeffery 
267fd883a88SAndrew Jeffery 		console->tty_sirq = (int)parsed;
2682834c5b1SAndrew Jeffery 		if (endp == optarg) {
269d66195c1SJeremy Kerr 			warn("Invalid sirq: '%s'", val);
270d66195c1SJeremy Kerr 		}
2712834c5b1SAndrew Jeffery 	}
272d66195c1SJeremy Kerr 
273c7fbcd48SBenjamin Fair 	val = config_get_value(config, "baud");
274c7fbcd48SBenjamin Fair 	if (val) {
2752834c5b1SAndrew Jeffery 		if (config_parse_baud(&console->tty_baud, val)) {
276c7fbcd48SBenjamin Fair 			warnx("Invalid baud rate: '%s'", val);
277c7fbcd48SBenjamin Fair 		}
2782834c5b1SAndrew Jeffery 	}
279c7fbcd48SBenjamin Fair 
280d66195c1SJeremy Kerr 	if (!console->tty_kname) {
281d66195c1SJeremy Kerr 		warnx("Error: No TTY device specified");
282d66195c1SJeremy Kerr 		return -1;
283d66195c1SJeremy Kerr 	}
284d66195c1SJeremy Kerr 
285d66195c1SJeremy Kerr 	rc = tty_find_device(console);
2862834c5b1SAndrew Jeffery 	if (rc) {
287d66195c1SJeremy Kerr 		return rc;
2882834c5b1SAndrew Jeffery 	}
289d66195c1SJeremy Kerr 
290d66195c1SJeremy Kerr 	rc = tty_init_io(console);
291d66195c1SJeremy Kerr 	return rc;
292d66195c1SJeremy Kerr }
293d66195c1SJeremy Kerr 
2941a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len)
295d831f960SJeremy Kerr {
2961a0e03b4SJeremy Kerr 	return write_buf_to_fd(console->tty_fd, data, len);
297d831f960SJeremy Kerr }
298d831f960SJeremy Kerr 
299b14ca19cSNinad Palsule /* Read console if from config and prepare a socket name */
300b14ca19cSNinad Palsule static int set_socket_info(struct console *console, struct config *config)
301b14ca19cSNinad Palsule {
302b14ca19cSNinad Palsule 	ssize_t len;
303b14ca19cSNinad Palsule 
304b14ca19cSNinad Palsule 	console->console_id = config_get_value(config, "socket-id");
305b14ca19cSNinad Palsule 	if (!console->console_id) {
306b14ca19cSNinad Palsule 		warnx("Error: The socket-id is not set in the config file");
307b14ca19cSNinad Palsule 		return EXIT_FAILURE;
308b14ca19cSNinad Palsule 	}
309b14ca19cSNinad Palsule 
310b14ca19cSNinad Palsule 	/* Get the socket name/path */
311b14ca19cSNinad Palsule 	len = console_socket_path(console->socket_name, console->console_id);
312b14ca19cSNinad Palsule 	if (len < 0) {
313b14ca19cSNinad Palsule 		warn("Failed to set socket path: %s", strerror(errno));
314b14ca19cSNinad Palsule 		return EXIT_FAILURE;
315b14ca19cSNinad Palsule 	}
316b14ca19cSNinad Palsule 
317b14ca19cSNinad Palsule 	/* Socket name is not a null terminated string hence save the length */
318b14ca19cSNinad Palsule 	console->socket_name_len = len;
319b14ca19cSNinad Palsule 
320b14ca19cSNinad Palsule 	return 0;
321b14ca19cSNinad Palsule }
322b14ca19cSNinad Palsule 
323d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config)
324d831f960SJeremy Kerr {
325b70f8713SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
326b70f8713SAndrew Jeffery 	extern struct handler *__start_handlers;
327b70f8713SAndrew Jeffery 	extern struct handler *__stop_handlers;
328b70f8713SAndrew Jeffery 	/* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
3291a0e03b4SJeremy Kerr 	struct handler *handler;
330b70f8713SAndrew Jeffery 	int i;
331b70f8713SAndrew Jeffery 	int rc;
332d831f960SJeremy Kerr 
3331a0e03b4SJeremy Kerr 	console->n_handlers = &__stop_handlers - &__start_handlers;
3341a0e03b4SJeremy Kerr 	console->handlers = &__start_handlers;
335d831f960SJeremy Kerr 
3365c359cc6SAndrew Jeffery 	printf("%ld handler%s\n", console->n_handlers,
3371a0e03b4SJeremy Kerr 	       console->n_handlers == 1 ? "" : "s");
338d831f960SJeremy Kerr 
3391a0e03b4SJeremy Kerr 	for (i = 0; i < console->n_handlers; i++) {
3401a0e03b4SJeremy Kerr 		handler = console->handlers[i];
3411a0e03b4SJeremy Kerr 
342021b91f0SJeremy Kerr 		rc = 0;
3432834c5b1SAndrew Jeffery 		if (handler->init) {
344021b91f0SJeremy Kerr 			rc = handler->init(handler, console, config);
3452834c5b1SAndrew Jeffery 		}
346021b91f0SJeremy Kerr 
347021b91f0SJeremy Kerr 		handler->active = rc == 0;
348021b91f0SJeremy Kerr 
349021b91f0SJeremy Kerr 		printf("  %s [%sactive]\n", handler->name,
350021b91f0SJeremy Kerr 		       handler->active ? "" : "in");
351d831f960SJeremy Kerr 	}
352d831f960SJeremy Kerr }
353d831f960SJeremy Kerr 
3541a0e03b4SJeremy Kerr static void handlers_fini(struct console *console)
355d831f960SJeremy Kerr {
3561a0e03b4SJeremy Kerr 	struct handler *handler;
3571a0e03b4SJeremy Kerr 	int i;
3581a0e03b4SJeremy Kerr 
3591a0e03b4SJeremy Kerr 	for (i = 0; i < console->n_handlers; i++) {
3601a0e03b4SJeremy Kerr 		handler = console->handlers[i];
3612834c5b1SAndrew Jeffery 		if (handler->fini && handler->active) {
3621a0e03b4SJeremy Kerr 			handler->fini(handler);
3631a0e03b4SJeremy Kerr 		}
364d831f960SJeremy Kerr 	}
3652834c5b1SAndrew Jeffery }
366d831f960SJeremy Kerr 
3671cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv)
3681cecc5deSJohnathan Mantey {
3691cecc5deSJohnathan Mantey 	struct timespec t;
3701cecc5deSJohnathan Mantey 	int rc;
3711cecc5deSJohnathan Mantey 
3721cecc5deSJohnathan Mantey 	/*
3731cecc5deSJohnathan Mantey 	 * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to
3741cecc5deSJohnathan Mantey 	 * local time changes. However, a struct timeval is more
3751cecc5deSJohnathan Mantey 	 * convenient for calculations, so convert to that.
3761cecc5deSJohnathan Mantey 	 */
3771cecc5deSJohnathan Mantey 	rc = clock_gettime(CLOCK_MONOTONIC, &t);
3782834c5b1SAndrew Jeffery 	if (rc) {
3791cecc5deSJohnathan Mantey 		return rc;
3802834c5b1SAndrew Jeffery 	}
3811cecc5deSJohnathan Mantey 
3821cecc5deSJohnathan Mantey 	tv->tv_sec = t.tv_sec;
3831cecc5deSJohnathan Mantey 	tv->tv_usec = t.tv_nsec / 1000;
3841cecc5deSJohnathan Mantey 
3851cecc5deSJohnathan Mantey 	return 0;
3861cecc5deSJohnathan Mantey }
3871cecc5deSJohnathan Mantey 
388a72711afSAndrew Jeffery struct ringbuffer_consumer *
389a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console,
390f733c85aSJeremy Kerr 				     ringbuffer_poll_fn_t poll_fn, void *data)
391d831f960SJeremy Kerr {
392f733c85aSJeremy Kerr 	return ringbuffer_consumer_register(console->rb, poll_fn, data);
393d831f960SJeremy Kerr }
394d831f960SJeremy Kerr 
39555c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console,
396a72711afSAndrew Jeffery 				       struct handler *handler,
397a72711afSAndrew Jeffery 				       poller_event_fn_t poller_fn,
3981cecc5deSJohnathan Mantey 				       poller_timeout_fn_t timeout_fn, int fd,
3991cecc5deSJohnathan Mantey 				       int events, void *data)
400d831f960SJeremy Kerr {
401329a35f5SJeremy Kerr 	struct poller *poller;
4025c359cc6SAndrew Jeffery 	long n;
403329a35f5SJeremy Kerr 
404329a35f5SJeremy Kerr 	poller = malloc(sizeof(*poller));
405329a35f5SJeremy Kerr 	poller->remove = false;
406329a35f5SJeremy Kerr 	poller->handler = handler;
4071cecc5deSJohnathan Mantey 	poller->event_fn = poller_fn;
4081cecc5deSJohnathan Mantey 	poller->timeout_fn = timeout_fn;
409329a35f5SJeremy Kerr 	poller->data = data;
410329a35f5SJeremy Kerr 
411329a35f5SJeremy Kerr 	/* add one to our pollers array */
412329a35f5SJeremy Kerr 	n = console->n_pollers++;
41391b52175SAndrew Jeffery 	/*
41491b52175SAndrew Jeffery 	 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
41591b52175SAndrew Jeffery 	 * pointer type.
41691b52175SAndrew Jeffery 	 */
41791b52175SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-sizeof-expression) */
41891b52175SAndrew Jeffery 	console->pollers = reallocarray(console->pollers, console->n_pollers,
41991b52175SAndrew Jeffery 					sizeof(*console->pollers));
42091b52175SAndrew Jeffery 	/* NOLINTEND(bugprone-sizeof-expression) */
421329a35f5SJeremy Kerr 
422329a35f5SJeremy Kerr 	console->pollers[n] = poller;
423329a35f5SJeremy Kerr 
424329a35f5SJeremy Kerr 	/* increase pollfds array too  */
425a72711afSAndrew Jeffery 	console->pollfds =
42691b52175SAndrew Jeffery 		reallocarray(console->pollfds,
42791b52175SAndrew Jeffery 			     (MAX_INTERNAL_POLLFD + console->n_pollers),
42891b52175SAndrew Jeffery 			     sizeof(*console->pollfds));
429329a35f5SJeremy Kerr 
430329a35f5SJeremy Kerr 	/* shift the end pollfds up by one */
431a72711afSAndrew Jeffery 	memcpy(&console->pollfds[n + 1], &console->pollfds[n],
432f9c8f6caSCheng C Yang 	       sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD);
433329a35f5SJeremy Kerr 
434329a35f5SJeremy Kerr 	console->pollfds[n].fd = fd;
4355c359cc6SAndrew Jeffery 	console->pollfds[n].events = (short)(events & 0x7fff);
436329a35f5SJeremy Kerr 
437329a35f5SJeremy Kerr 	return poller;
438329a35f5SJeremy Kerr }
439329a35f5SJeremy Kerr 
440a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller)
441329a35f5SJeremy Kerr {
442329a35f5SJeremy Kerr 	int i;
443329a35f5SJeremy Kerr 
444329a35f5SJeremy Kerr 	/* find the entry in our pollers array */
4452834c5b1SAndrew Jeffery 	for (i = 0; i < console->n_pollers; i++) {
4462834c5b1SAndrew Jeffery 		if (console->pollers[i] == poller) {
447329a35f5SJeremy Kerr 			break;
4482834c5b1SAndrew Jeffery 		}
4492834c5b1SAndrew Jeffery 	}
450329a35f5SJeremy Kerr 
451329a35f5SJeremy Kerr 	assert(i < console->n_pollers);
452329a35f5SJeremy Kerr 
453329a35f5SJeremy Kerr 	console->n_pollers--;
454329a35f5SJeremy Kerr 
45591b52175SAndrew Jeffery 	/*
45691b52175SAndrew Jeffery 	 * Remove the item from the pollers array...
45791b52175SAndrew Jeffery 	 *
45891b52175SAndrew Jeffery 	 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
45991b52175SAndrew Jeffery 	 * pointer type.
46091b52175SAndrew Jeffery 	 */
46191b52175SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-sizeof-expression) */
462329a35f5SJeremy Kerr 	memmove(&console->pollers[i], &console->pollers[i + 1],
463a72711afSAndrew Jeffery 		sizeof(*console->pollers) * (console->n_pollers - i));
464329a35f5SJeremy Kerr 
46591b52175SAndrew Jeffery 	console->pollers = reallocarray(console->pollers, console->n_pollers,
46691b52175SAndrew Jeffery 					sizeof(*console->pollers));
46791b52175SAndrew Jeffery 	/* NOLINTEND(bugprone-sizeof-expression) */
468329a35f5SJeremy Kerr 
469329a35f5SJeremy Kerr 	/* ... and the pollfds array */
470329a35f5SJeremy Kerr 	memmove(&console->pollfds[i], &console->pollfds[i + 1],
471329a35f5SJeremy Kerr 		sizeof(*console->pollfds) *
472f9c8f6caSCheng C Yang 			(MAX_INTERNAL_POLLFD + console->n_pollers - i));
473329a35f5SJeremy Kerr 
474a72711afSAndrew Jeffery 	console->pollfds =
47591b52175SAndrew Jeffery 		reallocarray(console->pollfds,
47691b52175SAndrew Jeffery 			     (MAX_INTERNAL_POLLFD + console->n_pollers),
47791b52175SAndrew Jeffery 			     sizeof(*console->pollfds));
478329a35f5SJeremy Kerr 
479329a35f5SJeremy Kerr 	free(poller);
480329a35f5SJeremy Kerr }
481329a35f5SJeremy Kerr 
4826b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller,
4836b1fed27SJeremy Kerr 			       int events)
4846b1fed27SJeremy Kerr {
4856b1fed27SJeremy Kerr 	int i;
4866b1fed27SJeremy Kerr 
4876b1fed27SJeremy Kerr 	/* find the entry in our pollers array */
4882834c5b1SAndrew Jeffery 	for (i = 0; i < console->n_pollers; i++) {
4892834c5b1SAndrew Jeffery 		if (console->pollers[i] == poller) {
4906b1fed27SJeremy Kerr 			break;
4912834c5b1SAndrew Jeffery 		}
4922834c5b1SAndrew Jeffery 	}
4936b1fed27SJeremy Kerr 
4945c359cc6SAndrew Jeffery 	console->pollfds[i].events = (short)(events & 0x7fff);
4956b1fed27SJeremy Kerr }
4966b1fed27SJeremy Kerr 
497fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)),
498fd048328SAndrew Jeffery 				struct poller *poller, const struct timeval *tv)
4991cecc5deSJohnathan Mantey {
5001cecc5deSJohnathan Mantey 	struct timeval now;
5011cecc5deSJohnathan Mantey 	int rc;
5021cecc5deSJohnathan Mantey 
5031cecc5deSJohnathan Mantey 	rc = get_current_time(&now);
5042834c5b1SAndrew Jeffery 	if (rc) {
5051cecc5deSJohnathan Mantey 		return;
5062834c5b1SAndrew Jeffery 	}
5071cecc5deSJohnathan Mantey 
5081cecc5deSJohnathan Mantey 	timeradd(&now, tv, &poller->timeout);
5091cecc5deSJohnathan Mantey }
5101cecc5deSJohnathan Mantey 
5115c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time)
5121cecc5deSJohnathan Mantey {
513b70f8713SAndrew Jeffery 	struct timeval *earliest;
514b70f8713SAndrew Jeffery 	struct timeval interval;
5151cecc5deSJohnathan Mantey 	struct poller *poller;
5161cecc5deSJohnathan Mantey 	int i;
5171cecc5deSJohnathan Mantey 
5181cecc5deSJohnathan Mantey 	earliest = NULL;
5191cecc5deSJohnathan Mantey 
5201cecc5deSJohnathan Mantey 	for (i = 0; i < console->n_pollers; i++) {
5211cecc5deSJohnathan Mantey 		poller = console->pollers[i];
5221cecc5deSJohnathan Mantey 
5231cecc5deSJohnathan Mantey 		if (poller->timeout_fn && timerisset(&poller->timeout) &&
5241cecc5deSJohnathan Mantey 		    (!earliest ||
5251cecc5deSJohnathan Mantey 		     (earliest && timercmp(&poller->timeout, earliest, <)))) {
5261cecc5deSJohnathan Mantey 			// poller is buffering data and needs the poll
5271cecc5deSJohnathan Mantey 			// function to timeout.
5281cecc5deSJohnathan Mantey 			earliest = &poller->timeout;
5291cecc5deSJohnathan Mantey 		}
5301cecc5deSJohnathan Mantey 	}
5311cecc5deSJohnathan Mantey 
5321cecc5deSJohnathan Mantey 	if (earliest) {
5331cecc5deSJohnathan Mantey 		if (timercmp(earliest, cur_time, >)) {
5341cecc5deSJohnathan Mantey 			/* recalculate the timeout period, time period has
5351cecc5deSJohnathan Mantey 			 * not elapsed */
5361cecc5deSJohnathan Mantey 			timersub(earliest, cur_time, &interval);
5371cecc5deSJohnathan Mantey 			return ((interval.tv_sec * 1000) +
5381cecc5deSJohnathan Mantey 				(interval.tv_usec / 1000));
5390b7b0477SAndrew Jeffery 		} /* return from poll immediately */
5401cecc5deSJohnathan Mantey 		return 0;
5410b7b0477SAndrew Jeffery 
5420b7b0477SAndrew Jeffery 	} /* poll indefinitely */
5431cecc5deSJohnathan Mantey 	return -1;
5441cecc5deSJohnathan Mantey }
5451cecc5deSJohnathan Mantey 
5461cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time)
547329a35f5SJeremy Kerr {
548329a35f5SJeremy Kerr 	struct poller *poller;
549329a35f5SJeremy Kerr 	struct pollfd *pollfd;
550329a35f5SJeremy Kerr 	enum poller_ret prc;
551b70f8713SAndrew Jeffery 	int i;
552b70f8713SAndrew Jeffery 	int rc;
553d831f960SJeremy Kerr 
5541a0e03b4SJeremy Kerr 	rc = 0;
5551a0e03b4SJeremy Kerr 
556329a35f5SJeremy Kerr 	/*
557329a35f5SJeremy Kerr 	 * Process poll events by iterating through the pollers and pollfds
558329a35f5SJeremy Kerr 	 * in-step, calling any pollers that we've found revents for.
559329a35f5SJeremy Kerr 	 */
560329a35f5SJeremy Kerr 	for (i = 0; i < console->n_pollers; i++) {
561329a35f5SJeremy Kerr 		poller = console->pollers[i];
562329a35f5SJeremy Kerr 		pollfd = &console->pollfds[i];
5631cecc5deSJohnathan Mantey 		prc = POLLER_OK;
5641a0e03b4SJeremy Kerr 
5651cecc5deSJohnathan Mantey 		/* process pending events... */
5661cecc5deSJohnathan Mantey 		if (pollfd->revents) {
5671cecc5deSJohnathan Mantey 			prc = poller->event_fn(poller->handler, pollfd->revents,
568329a35f5SJeremy Kerr 					       poller->data);
5692834c5b1SAndrew Jeffery 			if (prc == POLLER_EXIT) {
570329a35f5SJeremy Kerr 				rc = -1;
5712834c5b1SAndrew Jeffery 			} else if (prc == POLLER_REMOVE) {
572329a35f5SJeremy Kerr 				poller->remove = true;
573329a35f5SJeremy Kerr 			}
5742834c5b1SAndrew Jeffery 		}
575329a35f5SJeremy Kerr 
5761cecc5deSJohnathan Mantey 		if ((prc == POLLER_OK) && poller->timeout_fn &&
5771cecc5deSJohnathan Mantey 		    timerisset(&poller->timeout) &&
5781cecc5deSJohnathan Mantey 		    timercmp(&poller->timeout, cur_time, <=)) {
5791cecc5deSJohnathan Mantey 			/* One of the ringbuffer consumers is buffering the
5801cecc5deSJohnathan Mantey 			data stream. The amount of idle time the consumer
5811cecc5deSJohnathan Mantey 			desired has expired.  Process the buffered data for
5821cecc5deSJohnathan Mantey 			transmission. */
5831cecc5deSJohnathan Mantey 			timerclear(&poller->timeout);
5841cecc5deSJohnathan Mantey 			prc = poller->timeout_fn(poller->handler, poller->data);
5851cecc5deSJohnathan Mantey 			if (prc == POLLER_EXIT) {
5861cecc5deSJohnathan Mantey 				rc = -1;
5871cecc5deSJohnathan Mantey 			} else if (prc == POLLER_REMOVE) {
5881cecc5deSJohnathan Mantey 				poller->remove = true;
5891cecc5deSJohnathan Mantey 			}
5901cecc5deSJohnathan Mantey 		}
5911cecc5deSJohnathan Mantey 	}
5921cecc5deSJohnathan Mantey 
593329a35f5SJeremy Kerr 	/**
594329a35f5SJeremy Kerr 	 * Process deferred removals; restarting each time we unregister, as
595329a35f5SJeremy Kerr 	 * the array will have changed
596329a35f5SJeremy Kerr 	 */
597329a35f5SJeremy Kerr 	for (;;) {
598329a35f5SJeremy Kerr 		bool removed = false;
599329a35f5SJeremy Kerr 
600329a35f5SJeremy Kerr 		for (i = 0; i < console->n_pollers; i++) {
601329a35f5SJeremy Kerr 			poller = console->pollers[i];
602329a35f5SJeremy Kerr 			if (poller->remove) {
60355c9712dSJeremy Kerr 				console_poller_unregister(console, poller);
604329a35f5SJeremy Kerr 				removed = true;
605329a35f5SJeremy Kerr 				break;
606329a35f5SJeremy Kerr 			}
607329a35f5SJeremy Kerr 		}
6082834c5b1SAndrew Jeffery 		if (!removed) {
609329a35f5SJeremy Kerr 			break;
6101a0e03b4SJeremy Kerr 		}
6112834c5b1SAndrew Jeffery 	}
6121a0e03b4SJeremy Kerr 
6131a0e03b4SJeremy Kerr 	return rc;
6141a0e03b4SJeremy Kerr }
6151a0e03b4SJeremy Kerr 
616769cee1aSJeremy Kerr static void sighandler(int signal)
617769cee1aSJeremy Kerr {
6182834c5b1SAndrew Jeffery 	if (signal == SIGINT) {
619769cee1aSJeremy Kerr 		sigint = true;
620769cee1aSJeremy Kerr 	}
6212834c5b1SAndrew Jeffery }
622769cee1aSJeremy Kerr 
6231a0e03b4SJeremy Kerr int run_console(struct console *console)
6241a0e03b4SJeremy Kerr {
6255c359cc6SAndrew Jeffery 	sighandler_t sighandler_save = signal(SIGINT, sighandler);
6261cecc5deSJohnathan Mantey 	struct timeval tv;
6275c359cc6SAndrew Jeffery 	long timeout;
6285c359cc6SAndrew Jeffery 	ssize_t rc;
629769cee1aSJeremy Kerr 
630769cee1aSJeremy Kerr 	rc = 0;
631769cee1aSJeremy Kerr 
632d831f960SJeremy Kerr 	for (;;) {
633d831f960SJeremy Kerr 		uint8_t buf[4096];
634d831f960SJeremy Kerr 
6351764145dSJeremy Kerr 		BUILD_ASSERT(sizeof(buf) <= buffer_size);
6361764145dSJeremy Kerr 
637769cee1aSJeremy Kerr 		if (sigint) {
638769cee1aSJeremy Kerr 			fprintf(stderr, "Received interrupt, exiting\n");
639769cee1aSJeremy Kerr 			break;
640769cee1aSJeremy Kerr 		}
641769cee1aSJeremy Kerr 
6421cecc5deSJohnathan Mantey 		rc = get_current_time(&tv);
6431cecc5deSJohnathan Mantey 		if (rc) {
6441cecc5deSJohnathan Mantey 			warn("Failed to read current time");
6451cecc5deSJohnathan Mantey 			break;
6461cecc5deSJohnathan Mantey 		}
6471cecc5deSJohnathan Mantey 
6481cecc5deSJohnathan Mantey 		timeout = get_poll_timeout(console, &tv);
6491cecc5deSJohnathan Mantey 
650329a35f5SJeremy Kerr 		rc = poll(console->pollfds,
6515c359cc6SAndrew Jeffery 			  console->n_pollers + MAX_INTERNAL_POLLFD,
6525c359cc6SAndrew Jeffery 			  (int)timeout);
6531cecc5deSJohnathan Mantey 
654d831f960SJeremy Kerr 		if (rc < 0) {
655769cee1aSJeremy Kerr 			if (errno == EINTR) {
656769cee1aSJeremy Kerr 				continue;
6570b7b0477SAndrew Jeffery 			}
658d831f960SJeremy Kerr 			warn("poll error");
659769cee1aSJeremy Kerr 			break;
660769cee1aSJeremy Kerr 		}
661d831f960SJeremy Kerr 
662329a35f5SJeremy Kerr 		/* process internal fd first */
663329a35f5SJeremy Kerr 		if (console->pollfds[console->n_pollers].revents) {
6641a0e03b4SJeremy Kerr 			rc = read(console->tty_fd, buf, sizeof(buf));
665d831f960SJeremy Kerr 			if (rc <= 0) {
666d831f960SJeremy Kerr 				warn("Error reading from tty device");
667769cee1aSJeremy Kerr 				rc = -1;
668769cee1aSJeremy Kerr 				break;
669d831f960SJeremy Kerr 			}
670f733c85aSJeremy Kerr 			rc = ringbuffer_queue(console->rb, buf, rc);
6712834c5b1SAndrew Jeffery 			if (rc) {
672769cee1aSJeremy Kerr 				break;
673d831f960SJeremy Kerr 			}
6742834c5b1SAndrew Jeffery 		}
675d831f960SJeremy Kerr 
676f9c8f6caSCheng C Yang 		if (console->pollfds[console->n_pollers + 1].revents) {
677f9c8f6caSCheng C Yang 			sd_bus_process(console->bus, NULL);
678f9c8f6caSCheng C Yang 		}
679f9c8f6caSCheng C Yang 
680329a35f5SJeremy Kerr 		/* ... and then the pollers */
6811cecc5deSJohnathan Mantey 		rc = call_pollers(console, &tv);
6822834c5b1SAndrew Jeffery 		if (rc) {
683769cee1aSJeremy Kerr 			break;
6841a0e03b4SJeremy Kerr 		}
6852834c5b1SAndrew Jeffery 	}
686769cee1aSJeremy Kerr 
687769cee1aSJeremy Kerr 	signal(SIGINT, sighandler_save);
688f9c8f6caSCheng C Yang 	sd_bus_unref(console->bus);
689769cee1aSJeremy Kerr 
690769cee1aSJeremy Kerr 	return rc ? -1 : 0;
6911a0e03b4SJeremy Kerr }
692d831f960SJeremy Kerr static const struct option options[] = {
693d66195c1SJeremy Kerr 	{ "config", required_argument, 0, 'c' },
694f5858b5bSJoel Stanley 	{ 0, 0, 0, 0 },
695d831f960SJeremy Kerr };
696d831f960SJeremy Kerr 
697d831f960SJeremy Kerr int main(int argc, char **argv)
698d831f960SJeremy Kerr {
699d66195c1SJeremy Kerr 	const char *config_filename = NULL;
7006221ce94SVishwanatha Subbanna 	const char *config_tty_kname = NULL;
7011a0e03b4SJeremy Kerr 	struct console *console;
702d66195c1SJeremy Kerr 	struct config *config;
703d66195c1SJeremy Kerr 	int rc;
704d831f960SJeremy Kerr 
705957818b4SJeremy Kerr 	rc = -1;
706d831f960SJeremy Kerr 
707d831f960SJeremy Kerr 	for (;;) {
708b70f8713SAndrew Jeffery 		int c;
709b70f8713SAndrew Jeffery 		int idx;
710d831f960SJeremy Kerr 
711d66195c1SJeremy Kerr 		c = getopt_long(argc, argv, "c:", options, &idx);
7122834c5b1SAndrew Jeffery 		if (c == -1) {
713d831f960SJeremy Kerr 			break;
7142834c5b1SAndrew Jeffery 		}
715d831f960SJeremy Kerr 
716d831f960SJeremy Kerr 		switch (c) {
717d66195c1SJeremy Kerr 		case 'c':
718d66195c1SJeremy Kerr 			config_filename = optarg;
719d831f960SJeremy Kerr 			break;
720d831f960SJeremy Kerr 		case 'h':
721d831f960SJeremy Kerr 		case '?':
722d831f960SJeremy Kerr 			usage(argv[0]);
723d66195c1SJeremy Kerr 			return EXIT_SUCCESS;
724d831f960SJeremy Kerr 		}
725d831f960SJeremy Kerr 	}
726d831f960SJeremy Kerr 
7272834c5b1SAndrew Jeffery 	if (optind < argc) {
7286221ce94SVishwanatha Subbanna 		config_tty_kname = argv[optind];
7292834c5b1SAndrew Jeffery 	}
7306221ce94SVishwanatha Subbanna 
731d66195c1SJeremy Kerr 	console = malloc(sizeof(struct console));
732d66195c1SJeremy Kerr 	memset(console, 0, sizeof(*console));
733a72711afSAndrew Jeffery 	console->pollfds =
734a72711afSAndrew Jeffery 		calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds));
735f733c85aSJeremy Kerr 	console->rb = ringbuffer_init(buffer_size);
736329a35f5SJeremy Kerr 
737d66195c1SJeremy Kerr 	config = config_init(config_filename);
738d66195c1SJeremy Kerr 	if (!config) {
739d66195c1SJeremy Kerr 		warnx("Can't read configuration, exiting.");
740d66195c1SJeremy Kerr 		goto out_free;
741d831f960SJeremy Kerr 	}
742d831f960SJeremy Kerr 
7432834c5b1SAndrew Jeffery 	if (!config_tty_kname) {
74491dde14eSAndrew Jeffery 		config_tty_kname = config_get_value(config, "upstream-tty");
7452834c5b1SAndrew Jeffery 	}
74691dde14eSAndrew Jeffery 
74791dde14eSAndrew Jeffery 	if (!config_tty_kname) {
74891dde14eSAndrew Jeffery 		warnx("No TTY device specified");
74991dde14eSAndrew Jeffery 		usage(argv[0]);
75091dde14eSAndrew Jeffery 		return EXIT_FAILURE;
75191dde14eSAndrew Jeffery 	}
75291dde14eSAndrew Jeffery 
753b14ca19cSNinad Palsule 	if (set_socket_info(console, config)) {
754b14ca19cSNinad Palsule 		return EXIT_FAILURE;
755b14ca19cSNinad Palsule 	}
756b14ca19cSNinad Palsule 
7576221ce94SVishwanatha Subbanna 	console->tty_kname = config_tty_kname;
7586221ce94SVishwanatha Subbanna 
7594e718691SNinad Palsule 	console->console_id = config_get_value(config, "socket-id");
7604e718691SNinad Palsule 	if (!console->console_id) {
7614e718691SNinad Palsule 		warnx("Error: The socket-id is not set in the config file");
7624e718691SNinad Palsule 		return EXIT_FAILURE;
7634e718691SNinad Palsule 	}
7644e718691SNinad Palsule 
765d66195c1SJeremy Kerr 	rc = tty_init(console, config);
7662834c5b1SAndrew Jeffery 	if (rc) {
767d66195c1SJeremy Kerr 		goto out_config_fini;
7682834c5b1SAndrew Jeffery 	}
769d831f960SJeremy Kerr 
770f9c8f6caSCheng C Yang 	dbus_init(console, config);
771f9c8f6caSCheng C Yang 
772d47963e5SJeremy Kerr 	handlers_init(console, config);
773d831f960SJeremy Kerr 
7741a0e03b4SJeremy Kerr 	rc = run_console(console);
775d831f960SJeremy Kerr 
7761a0e03b4SJeremy Kerr 	handlers_fini(console);
777d831f960SJeremy Kerr 
778d66195c1SJeremy Kerr out_config_fini:
779d66195c1SJeremy Kerr 	config_fini(config);
780d66195c1SJeremy Kerr 
781957818b4SJeremy Kerr out_free:
78289ea8198SJeremy Kerr 	free(console->pollers);
78389ea8198SJeremy Kerr 	free(console->pollfds);
7841a0e03b4SJeremy Kerr 	free(console->tty_sysfs_devnode);
7851a0e03b4SJeremy Kerr 	free(console->tty_dev);
7861a0e03b4SJeremy Kerr 	free(console);
787d831f960SJeremy Kerr 
788d831f960SJeremy Kerr 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
789d831f960SJeremy Kerr }
790