xref: /openbmc/obmc-console/console-server.c (revision b14ca19cf380efbf7a96a348cc6fc81e75bf0591)
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>
37*b14ca19cSNinad 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 {
6217217845SJeremy Kerr 	char *tty_class_device_link;
6317217845SJeremy Kerr 	char *tty_device_tty_dir;
6417217845SJeremy Kerr 	char *tty_device_reldir;
6545ad7676SYi Li 	char *tty_path_input;
6645ad7676SYi Li 	char *tty_path_input_real;
6745ad7676SYi Li 	char *tty_kname_real;
6817217845SJeremy Kerr 	int rc;
6917217845SJeremy Kerr 
7017217845SJeremy Kerr 	tty_class_device_link = NULL;
7117217845SJeremy Kerr 	tty_device_tty_dir = NULL;
7217217845SJeremy Kerr 	tty_device_reldir = NULL;
7345ad7676SYi Li 	tty_path_input = NULL;
7445ad7676SYi Li 	tty_path_input_real = NULL;
7545ad7676SYi Li 	tty_kname_real = NULL;
7617217845SJeremy Kerr 
7745ad7676SYi Li 	/* udev may rename the tty name with a symbol link, try to resolve */
7845ad7676SYi Li 	rc = asprintf(&tty_path_input, "/dev/%s", console->tty_kname);
792834c5b1SAndrew Jeffery 	if (rc < 0) {
8017217845SJeremy Kerr 		return -1;
812834c5b1SAndrew Jeffery 	}
8217217845SJeremy Kerr 
8345ad7676SYi Li 	tty_path_input_real = realpath(tty_path_input, NULL);
8445ad7676SYi Li 	if (!tty_path_input_real) {
8545ad7676SYi Li 		warn("Can't find realpath for /dev/%s", console->tty_kname);
8615792aa7SAndrew Jeffery 		rc = -1;
8745ad7676SYi Li 		goto out_free;
8845ad7676SYi Li 	}
8945ad7676SYi Li 
9045ad7676SYi Li 	tty_kname_real = basename(tty_path_input_real);
9145ad7676SYi Li 	if (!tty_kname_real) {
9245ad7676SYi Li 		warn("Can't find real name for /dev/%s", console->tty_kname);
9315792aa7SAndrew Jeffery 		rc = -1;
9445ad7676SYi Li 		goto out_free;
9545ad7676SYi Li 	}
9645ad7676SYi Li 
97a72711afSAndrew Jeffery 	rc = asprintf(&tty_class_device_link, "/sys/class/tty/%s",
98a72711afSAndrew Jeffery 		      tty_kname_real);
992834c5b1SAndrew Jeffery 	if (rc < 0) {
10045ad7676SYi Li 		goto out_free;
1012834c5b1SAndrew Jeffery 	}
10245ad7676SYi Li 
10317217845SJeremy Kerr 	tty_device_tty_dir = realpath(tty_class_device_link, NULL);
10445ad7676SYi Li 	if (!tty_device_tty_dir) {
10545ad7676SYi Li 		warn("Can't query sysfs for device %s", tty_kname_real);
10615792aa7SAndrew Jeffery 		rc = -1;
10717217845SJeremy Kerr 		goto out_free;
10817217845SJeremy Kerr 	}
10917217845SJeremy Kerr 
11017217845SJeremy Kerr 	rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir);
1112834c5b1SAndrew Jeffery 	if (rc < 0) {
11217217845SJeremy Kerr 		goto out_free;
1132834c5b1SAndrew Jeffery 	}
11417217845SJeremy Kerr 
1151a0e03b4SJeremy Kerr 	console->tty_sysfs_devnode = realpath(tty_device_reldir, NULL);
1162834c5b1SAndrew Jeffery 	if (!console->tty_sysfs_devnode) {
11745ad7676SYi Li 		warn("Can't find parent device for %s", tty_kname_real);
1182834c5b1SAndrew Jeffery 	}
11917217845SJeremy Kerr 
12045ad7676SYi Li 	rc = asprintf(&console->tty_dev, "/dev/%s", tty_kname_real);
1212834c5b1SAndrew Jeffery 	if (rc < 0) {
12217217845SJeremy Kerr 		goto out_free;
1232834c5b1SAndrew Jeffery 	}
12417217845SJeremy Kerr 
12517217845SJeremy Kerr 	rc = 0;
12617217845SJeremy Kerr 
12717217845SJeremy Kerr out_free:
12817217845SJeremy Kerr 	free(tty_class_device_link);
12917217845SJeremy Kerr 	free(tty_device_tty_dir);
13017217845SJeremy Kerr 	free(tty_device_reldir);
13145ad7676SYi Li 	free(tty_path_input);
13245ad7676SYi Li 	free(tty_path_input_real);
13317217845SJeremy Kerr 	return rc;
13417217845SJeremy Kerr }
13517217845SJeremy Kerr 
1361a0e03b4SJeremy Kerr static int tty_set_sysfs_attr(struct console *console, const char *name,
137957818b4SJeremy Kerr 			      int value)
138957818b4SJeremy Kerr {
139957818b4SJeremy Kerr 	char *path;
140957818b4SJeremy Kerr 	FILE *fp;
141957818b4SJeremy Kerr 	int rc;
142957818b4SJeremy Kerr 
1431a0e03b4SJeremy Kerr 	rc = asprintf(&path, "%s/%s", console->tty_sysfs_devnode, name);
1442834c5b1SAndrew Jeffery 	if (rc < 0) {
145957818b4SJeremy Kerr 		return -1;
1462834c5b1SAndrew Jeffery 	}
147957818b4SJeremy Kerr 
148957818b4SJeremy Kerr 	fp = fopen(path, "w");
149957818b4SJeremy Kerr 	if (!fp) {
150a72711afSAndrew Jeffery 		warn("Can't access attribute %s on device %s", name,
151a72711afSAndrew Jeffery 		     console->tty_kname);
152957818b4SJeremy Kerr 		rc = -1;
153957818b4SJeremy Kerr 		goto out_free;
154957818b4SJeremy Kerr 	}
155957818b4SJeremy Kerr 	setvbuf(fp, NULL, _IONBF, 0);
156957818b4SJeremy Kerr 
157957818b4SJeremy Kerr 	rc = fprintf(fp, "0x%x", value);
1582834c5b1SAndrew Jeffery 	if (rc < 0) {
159a72711afSAndrew Jeffery 		warn("Error writing to %s attribute of device %s", name,
160a72711afSAndrew Jeffery 		     console->tty_kname);
1612834c5b1SAndrew Jeffery 	}
162957818b4SJeremy Kerr 	fclose(fp);
163957818b4SJeremy Kerr 
164957818b4SJeremy Kerr out_free:
165957818b4SJeremy Kerr 	free(path);
166957818b4SJeremy Kerr 	return rc;
167957818b4SJeremy Kerr }
168957818b4SJeremy Kerr 
169d831f960SJeremy Kerr /**
170c7fbcd48SBenjamin Fair  * Set termios attributes on the console tty.
17154e9569dSJeremy Kerr  */
172e258e51fSNinad Palsule void tty_init_termios(struct console *console)
17354e9569dSJeremy Kerr {
17454e9569dSJeremy Kerr 	struct termios termios;
17554e9569dSJeremy Kerr 	int rc;
17654e9569dSJeremy Kerr 
17754e9569dSJeremy Kerr 	rc = tcgetattr(console->tty_fd, &termios);
17854e9569dSJeremy Kerr 	if (rc) {
17954e9569dSJeremy Kerr 		warn("Can't read tty termios");
18054e9569dSJeremy Kerr 		return;
18154e9569dSJeremy Kerr 	}
18254e9569dSJeremy Kerr 
183c7fbcd48SBenjamin Fair 	if (console->tty_baud) {
1842834c5b1SAndrew Jeffery 		if (cfsetspeed(&termios, console->tty_baud) < 0) {
185c7fbcd48SBenjamin Fair 			warn("Couldn't set speeds for %s", console->tty_kname);
186c7fbcd48SBenjamin Fair 		}
1872834c5b1SAndrew Jeffery 	}
188c7fbcd48SBenjamin Fair 
189c7fbcd48SBenjamin Fair 	/* Set console to raw mode: we don't want any processing to occur on
190c7fbcd48SBenjamin Fair 	 * the underlying terminal input/output.
191c7fbcd48SBenjamin Fair 	 */
19254e9569dSJeremy Kerr 	cfmakeraw(&termios);
193c7fbcd48SBenjamin Fair 
19454e9569dSJeremy Kerr 	rc = tcsetattr(console->tty_fd, TCSANOW, &termios);
1952834c5b1SAndrew Jeffery 	if (rc) {
196c7fbcd48SBenjamin Fair 		warn("Can't set terminal options for %s", console->tty_kname);
19754e9569dSJeremy Kerr 	}
1982834c5b1SAndrew Jeffery }
19954e9569dSJeremy Kerr 
20054e9569dSJeremy Kerr /**
201d831f960SJeremy Kerr  * Open and initialise the serial device
202d831f960SJeremy Kerr  */
2031a0e03b4SJeremy Kerr static int tty_init_io(struct console *console)
204d831f960SJeremy Kerr {
2052834c5b1SAndrew Jeffery 	if (console->tty_sirq) {
2061a0e03b4SJeremy Kerr 		tty_set_sysfs_attr(console, "sirq", console->tty_sirq);
2072834c5b1SAndrew Jeffery 	}
2082834c5b1SAndrew Jeffery 	if (console->tty_lpc_addr) {
2091a0e03b4SJeremy Kerr 		tty_set_sysfs_attr(console, "lpc_address",
2101a0e03b4SJeremy Kerr 				   console->tty_lpc_addr);
2112834c5b1SAndrew Jeffery 	}
212957818b4SJeremy Kerr 
2131a0e03b4SJeremy Kerr 	console->tty_fd = open(console->tty_dev, O_RDWR);
2141a0e03b4SJeremy Kerr 	if (console->tty_fd <= 0) {
2151a0e03b4SJeremy Kerr 		warn("Can't open tty %s", console->tty_dev);
216d831f960SJeremy Kerr 		return -1;
217d831f960SJeremy Kerr 	}
218d831f960SJeremy Kerr 
219d831f960SJeremy Kerr 	/* Disable character delay. We may want to later enable this when
220d831f960SJeremy Kerr 	 * we detect larger amounts of data
221d831f960SJeremy Kerr 	 */
2221a0e03b4SJeremy Kerr 	fcntl(console->tty_fd, F_SETFL, FNDELAY);
223d831f960SJeremy Kerr 
22454e9569dSJeremy Kerr 	tty_init_termios(console);
22554e9569dSJeremy Kerr 
226329a35f5SJeremy Kerr 	console->pollfds[console->n_pollers].fd = console->tty_fd;
227329a35f5SJeremy Kerr 	console->pollfds[console->n_pollers].events = POLLIN;
228329a35f5SJeremy Kerr 
229d831f960SJeremy Kerr 	return 0;
230d831f960SJeremy Kerr }
231d831f960SJeremy Kerr 
232d66195c1SJeremy Kerr static int tty_init(struct console *console, struct config *config)
233d66195c1SJeremy Kerr {
234fd883a88SAndrew Jeffery 	unsigned long parsed;
235d66195c1SJeremy Kerr 	const char *val;
236d66195c1SJeremy Kerr 	char *endp;
237d66195c1SJeremy Kerr 	int rc;
238d66195c1SJeremy Kerr 
239d66195c1SJeremy Kerr 	val = config_get_value(config, "lpc-address");
240d66195c1SJeremy Kerr 	if (val) {
241fd883a88SAndrew Jeffery 		errno = 0;
242fd883a88SAndrew Jeffery 		parsed = strtoul(val, &endp, 0);
243fd883a88SAndrew Jeffery 		if (parsed == ULONG_MAX && errno == ERANGE) {
244fd883a88SAndrew Jeffery 			warn("Cannot interpret 'lpc-address' value as an unsigned long: '%s'",
245fd883a88SAndrew Jeffery 			     val);
246fd883a88SAndrew Jeffery 			return -1;
247fd883a88SAndrew Jeffery 		}
248fd883a88SAndrew Jeffery 
249fd883a88SAndrew Jeffery 		if (parsed > UINT16_MAX) {
250fd883a88SAndrew Jeffery 			warn("Invalid LPC address '%s'", val);
251fd883a88SAndrew Jeffery 			return -1;
252fd883a88SAndrew Jeffery 		}
253fd883a88SAndrew Jeffery 
254fd883a88SAndrew Jeffery 		console->tty_lpc_addr = (uint16_t)parsed;
255d66195c1SJeremy Kerr 		if (endp == optarg) {
256d66195c1SJeremy Kerr 			warn("Invalid LPC address: '%s'", val);
257d66195c1SJeremy Kerr 			return -1;
258d66195c1SJeremy Kerr 		}
259d66195c1SJeremy Kerr 	}
260d66195c1SJeremy Kerr 
261d66195c1SJeremy Kerr 	val = config_get_value(config, "sirq");
262d66195c1SJeremy Kerr 	if (val) {
263fd883a88SAndrew Jeffery 		errno = 0;
264fd883a88SAndrew Jeffery 		parsed = strtoul(val, &endp, 0);
265fd883a88SAndrew Jeffery 		if (parsed == ULONG_MAX && errno == ERANGE) {
266fd883a88SAndrew Jeffery 			warn("Cannot interpret 'sirq' value as an unsigned long: '%s'",
267fd883a88SAndrew Jeffery 			     val);
268fd883a88SAndrew Jeffery 		}
269fd883a88SAndrew Jeffery 
2702834c5b1SAndrew Jeffery 		if (parsed > 16) {
271fd883a88SAndrew Jeffery 			warn("Invalid LPC SERIRQ: '%s'", val);
2722834c5b1SAndrew Jeffery 		}
273fd883a88SAndrew Jeffery 
274fd883a88SAndrew Jeffery 		console->tty_sirq = (int)parsed;
2752834c5b1SAndrew Jeffery 		if (endp == optarg) {
276d66195c1SJeremy Kerr 			warn("Invalid sirq: '%s'", val);
277d66195c1SJeremy Kerr 		}
2782834c5b1SAndrew Jeffery 	}
279d66195c1SJeremy Kerr 
280c7fbcd48SBenjamin Fair 	val = config_get_value(config, "baud");
281c7fbcd48SBenjamin Fair 	if (val) {
2822834c5b1SAndrew Jeffery 		if (config_parse_baud(&console->tty_baud, val)) {
283c7fbcd48SBenjamin Fair 			warnx("Invalid baud rate: '%s'", val);
284c7fbcd48SBenjamin Fair 		}
2852834c5b1SAndrew Jeffery 	}
286c7fbcd48SBenjamin Fair 
287d66195c1SJeremy Kerr 	if (!console->tty_kname) {
288d66195c1SJeremy Kerr 		warnx("Error: No TTY device specified");
289d66195c1SJeremy Kerr 		return -1;
290d66195c1SJeremy Kerr 	}
291d66195c1SJeremy Kerr 
292d66195c1SJeremy Kerr 	rc = tty_find_device(console);
2932834c5b1SAndrew Jeffery 	if (rc) {
294d66195c1SJeremy Kerr 		return rc;
2952834c5b1SAndrew Jeffery 	}
296d66195c1SJeremy Kerr 
297d66195c1SJeremy Kerr 	rc = tty_init_io(console);
298d66195c1SJeremy Kerr 	return rc;
299d66195c1SJeremy Kerr }
300d66195c1SJeremy Kerr 
3011a0e03b4SJeremy Kerr int console_data_out(struct console *console, const uint8_t *data, size_t len)
302d831f960SJeremy Kerr {
3031a0e03b4SJeremy Kerr 	return write_buf_to_fd(console->tty_fd, data, len);
304d831f960SJeremy Kerr }
305d831f960SJeremy Kerr 
306*b14ca19cSNinad Palsule /* Read console if from config and prepare a socket name */
307*b14ca19cSNinad Palsule static int set_socket_info(struct console *console, struct config *config)
308*b14ca19cSNinad Palsule {
309*b14ca19cSNinad Palsule 	ssize_t len;
310*b14ca19cSNinad Palsule 
311*b14ca19cSNinad Palsule 	console->console_id = config_get_value(config, "socket-id");
312*b14ca19cSNinad Palsule 	if (!console->console_id) {
313*b14ca19cSNinad Palsule 		warnx("Error: The socket-id is not set in the config file");
314*b14ca19cSNinad Palsule 		return EXIT_FAILURE;
315*b14ca19cSNinad Palsule 	}
316*b14ca19cSNinad Palsule 
317*b14ca19cSNinad Palsule 	/* Get the socket name/path */
318*b14ca19cSNinad Palsule 	len = console_socket_path(console->socket_name, console->console_id);
319*b14ca19cSNinad Palsule 	if (len < 0) {
320*b14ca19cSNinad Palsule 		warn("Failed to set socket path: %s", strerror(errno));
321*b14ca19cSNinad Palsule 		return EXIT_FAILURE;
322*b14ca19cSNinad Palsule 	}
323*b14ca19cSNinad Palsule 
324*b14ca19cSNinad Palsule 	/* Socket name is not a null terminated string hence save the length */
325*b14ca19cSNinad Palsule 	console->socket_name_len = len;
326*b14ca19cSNinad Palsule 
327*b14ca19cSNinad Palsule 	return 0;
328*b14ca19cSNinad Palsule }
329*b14ca19cSNinad Palsule 
330d47963e5SJeremy Kerr static void handlers_init(struct console *console, struct config *config)
331d831f960SJeremy Kerr {
332b70f8713SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
333b70f8713SAndrew Jeffery 	extern struct handler *__start_handlers;
334b70f8713SAndrew Jeffery 	extern struct handler *__stop_handlers;
335b70f8713SAndrew Jeffery 	/* NOLINTEND(bugprone-reserved-identifier,cert-dcl37-c,cert-dcl51-cpp) */
3361a0e03b4SJeremy Kerr 	struct handler *handler;
337b70f8713SAndrew Jeffery 	int i;
338b70f8713SAndrew Jeffery 	int rc;
339d831f960SJeremy Kerr 
3401a0e03b4SJeremy Kerr 	console->n_handlers = &__stop_handlers - &__start_handlers;
3411a0e03b4SJeremy Kerr 	console->handlers = &__start_handlers;
342d831f960SJeremy Kerr 
3435c359cc6SAndrew Jeffery 	printf("%ld handler%s\n", console->n_handlers,
3441a0e03b4SJeremy Kerr 	       console->n_handlers == 1 ? "" : "s");
345d831f960SJeremy Kerr 
3461a0e03b4SJeremy Kerr 	for (i = 0; i < console->n_handlers; i++) {
3471a0e03b4SJeremy Kerr 		handler = console->handlers[i];
3481a0e03b4SJeremy Kerr 
349021b91f0SJeremy Kerr 		rc = 0;
3502834c5b1SAndrew Jeffery 		if (handler->init) {
351021b91f0SJeremy Kerr 			rc = handler->init(handler, console, config);
3522834c5b1SAndrew Jeffery 		}
353021b91f0SJeremy Kerr 
354021b91f0SJeremy Kerr 		handler->active = rc == 0;
355021b91f0SJeremy Kerr 
356021b91f0SJeremy Kerr 		printf("  %s [%sactive]\n", handler->name,
357021b91f0SJeremy Kerr 		       handler->active ? "" : "in");
358d831f960SJeremy Kerr 	}
359d831f960SJeremy Kerr }
360d831f960SJeremy Kerr 
3611a0e03b4SJeremy Kerr static void handlers_fini(struct console *console)
362d831f960SJeremy Kerr {
3631a0e03b4SJeremy Kerr 	struct handler *handler;
3641a0e03b4SJeremy Kerr 	int i;
3651a0e03b4SJeremy Kerr 
3661a0e03b4SJeremy Kerr 	for (i = 0; i < console->n_handlers; i++) {
3671a0e03b4SJeremy Kerr 		handler = console->handlers[i];
3682834c5b1SAndrew Jeffery 		if (handler->fini && handler->active) {
3691a0e03b4SJeremy Kerr 			handler->fini(handler);
3701a0e03b4SJeremy Kerr 		}
371d831f960SJeremy Kerr 	}
3722834c5b1SAndrew Jeffery }
373d831f960SJeremy Kerr 
3741cecc5deSJohnathan Mantey static int get_current_time(struct timeval *tv)
3751cecc5deSJohnathan Mantey {
3761cecc5deSJohnathan Mantey 	struct timespec t;
3771cecc5deSJohnathan Mantey 	int rc;
3781cecc5deSJohnathan Mantey 
3791cecc5deSJohnathan Mantey 	/*
3801cecc5deSJohnathan Mantey 	 * We use clock_gettime(CLOCK_MONOTONIC) so we're immune to
3811cecc5deSJohnathan Mantey 	 * local time changes. However, a struct timeval is more
3821cecc5deSJohnathan Mantey 	 * convenient for calculations, so convert to that.
3831cecc5deSJohnathan Mantey 	 */
3841cecc5deSJohnathan Mantey 	rc = clock_gettime(CLOCK_MONOTONIC, &t);
3852834c5b1SAndrew Jeffery 	if (rc) {
3861cecc5deSJohnathan Mantey 		return rc;
3872834c5b1SAndrew Jeffery 	}
3881cecc5deSJohnathan Mantey 
3891cecc5deSJohnathan Mantey 	tv->tv_sec = t.tv_sec;
3901cecc5deSJohnathan Mantey 	tv->tv_usec = t.tv_nsec / 1000;
3911cecc5deSJohnathan Mantey 
3921cecc5deSJohnathan Mantey 	return 0;
3931cecc5deSJohnathan Mantey }
3941cecc5deSJohnathan Mantey 
395a72711afSAndrew Jeffery struct ringbuffer_consumer *
396a72711afSAndrew Jeffery console_ringbuffer_consumer_register(struct console *console,
397f733c85aSJeremy Kerr 				     ringbuffer_poll_fn_t poll_fn, void *data)
398d831f960SJeremy Kerr {
399f733c85aSJeremy Kerr 	return ringbuffer_consumer_register(console->rb, poll_fn, data);
400d831f960SJeremy Kerr }
401d831f960SJeremy Kerr 
40255c9712dSJeremy Kerr struct poller *console_poller_register(struct console *console,
403a72711afSAndrew Jeffery 				       struct handler *handler,
404a72711afSAndrew Jeffery 				       poller_event_fn_t poller_fn,
4051cecc5deSJohnathan Mantey 				       poller_timeout_fn_t timeout_fn, int fd,
4061cecc5deSJohnathan Mantey 				       int events, void *data)
407d831f960SJeremy Kerr {
408329a35f5SJeremy Kerr 	struct poller *poller;
4095c359cc6SAndrew Jeffery 	long n;
410329a35f5SJeremy Kerr 
411329a35f5SJeremy Kerr 	poller = malloc(sizeof(*poller));
412329a35f5SJeremy Kerr 	poller->remove = false;
413329a35f5SJeremy Kerr 	poller->handler = handler;
4141cecc5deSJohnathan Mantey 	poller->event_fn = poller_fn;
4151cecc5deSJohnathan Mantey 	poller->timeout_fn = timeout_fn;
416329a35f5SJeremy Kerr 	poller->data = data;
417329a35f5SJeremy Kerr 
418329a35f5SJeremy Kerr 	/* add one to our pollers array */
419329a35f5SJeremy Kerr 	n = console->n_pollers++;
42091b52175SAndrew Jeffery 	/*
42191b52175SAndrew Jeffery 	 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
42291b52175SAndrew Jeffery 	 * pointer type.
42391b52175SAndrew Jeffery 	 */
42491b52175SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-sizeof-expression) */
42591b52175SAndrew Jeffery 	console->pollers = reallocarray(console->pollers, console->n_pollers,
42691b52175SAndrew Jeffery 					sizeof(*console->pollers));
42791b52175SAndrew Jeffery 	/* NOLINTEND(bugprone-sizeof-expression) */
428329a35f5SJeremy Kerr 
429329a35f5SJeremy Kerr 	console->pollers[n] = poller;
430329a35f5SJeremy Kerr 
431329a35f5SJeremy Kerr 	/* increase pollfds array too  */
432a72711afSAndrew Jeffery 	console->pollfds =
43391b52175SAndrew Jeffery 		reallocarray(console->pollfds,
43491b52175SAndrew Jeffery 			     (MAX_INTERNAL_POLLFD + console->n_pollers),
43591b52175SAndrew Jeffery 			     sizeof(*console->pollfds));
436329a35f5SJeremy Kerr 
437329a35f5SJeremy Kerr 	/* shift the end pollfds up by one */
438a72711afSAndrew Jeffery 	memcpy(&console->pollfds[n + 1], &console->pollfds[n],
439f9c8f6caSCheng C Yang 	       sizeof(*console->pollfds) * MAX_INTERNAL_POLLFD);
440329a35f5SJeremy Kerr 
441329a35f5SJeremy Kerr 	console->pollfds[n].fd = fd;
4425c359cc6SAndrew Jeffery 	console->pollfds[n].events = (short)(events & 0x7fff);
443329a35f5SJeremy Kerr 
444329a35f5SJeremy Kerr 	return poller;
445329a35f5SJeremy Kerr }
446329a35f5SJeremy Kerr 
447a72711afSAndrew Jeffery void console_poller_unregister(struct console *console, struct poller *poller)
448329a35f5SJeremy Kerr {
449329a35f5SJeremy Kerr 	int i;
450329a35f5SJeremy Kerr 
451329a35f5SJeremy Kerr 	/* find the entry in our pollers array */
4522834c5b1SAndrew Jeffery 	for (i = 0; i < console->n_pollers; i++) {
4532834c5b1SAndrew Jeffery 		if (console->pollers[i] == poller) {
454329a35f5SJeremy Kerr 			break;
4552834c5b1SAndrew Jeffery 		}
4562834c5b1SAndrew Jeffery 	}
457329a35f5SJeremy Kerr 
458329a35f5SJeremy Kerr 	assert(i < console->n_pollers);
459329a35f5SJeremy Kerr 
460329a35f5SJeremy Kerr 	console->n_pollers--;
461329a35f5SJeremy Kerr 
46291b52175SAndrew Jeffery 	/*
46391b52175SAndrew Jeffery 	 * Remove the item from the pollers array...
46491b52175SAndrew Jeffery 	 *
46591b52175SAndrew Jeffery 	 * We're managing an array of pointers to aggregates, so don't warn about sizeof() on a
46691b52175SAndrew Jeffery 	 * pointer type.
46791b52175SAndrew Jeffery 	 */
46891b52175SAndrew Jeffery 	/* NOLINTBEGIN(bugprone-sizeof-expression) */
469329a35f5SJeremy Kerr 	memmove(&console->pollers[i], &console->pollers[i + 1],
470a72711afSAndrew Jeffery 		sizeof(*console->pollers) * (console->n_pollers - i));
471329a35f5SJeremy Kerr 
47291b52175SAndrew Jeffery 	console->pollers = reallocarray(console->pollers, console->n_pollers,
47391b52175SAndrew Jeffery 					sizeof(*console->pollers));
47491b52175SAndrew Jeffery 	/* NOLINTEND(bugprone-sizeof-expression) */
475329a35f5SJeremy Kerr 
476329a35f5SJeremy Kerr 	/* ... and the pollfds array */
477329a35f5SJeremy Kerr 	memmove(&console->pollfds[i], &console->pollfds[i + 1],
478329a35f5SJeremy Kerr 		sizeof(*console->pollfds) *
479f9c8f6caSCheng C Yang 			(MAX_INTERNAL_POLLFD + console->n_pollers - i));
480329a35f5SJeremy Kerr 
481a72711afSAndrew Jeffery 	console->pollfds =
48291b52175SAndrew Jeffery 		reallocarray(console->pollfds,
48391b52175SAndrew Jeffery 			     (MAX_INTERNAL_POLLFD + console->n_pollers),
48491b52175SAndrew Jeffery 			     sizeof(*console->pollfds));
485329a35f5SJeremy Kerr 
486329a35f5SJeremy Kerr 	free(poller);
487329a35f5SJeremy Kerr }
488329a35f5SJeremy Kerr 
4896b1fed27SJeremy Kerr void console_poller_set_events(struct console *console, struct poller *poller,
4906b1fed27SJeremy Kerr 			       int events)
4916b1fed27SJeremy Kerr {
4926b1fed27SJeremy Kerr 	int i;
4936b1fed27SJeremy Kerr 
4946b1fed27SJeremy Kerr 	/* find the entry in our pollers array */
4952834c5b1SAndrew Jeffery 	for (i = 0; i < console->n_pollers; i++) {
4962834c5b1SAndrew Jeffery 		if (console->pollers[i] == poller) {
4976b1fed27SJeremy Kerr 			break;
4982834c5b1SAndrew Jeffery 		}
4992834c5b1SAndrew Jeffery 	}
5006b1fed27SJeremy Kerr 
5015c359cc6SAndrew Jeffery 	console->pollfds[i].events = (short)(events & 0x7fff);
5026b1fed27SJeremy Kerr }
5036b1fed27SJeremy Kerr 
504fd048328SAndrew Jeffery void console_poller_set_timeout(struct console *console __attribute__((unused)),
505fd048328SAndrew Jeffery 				struct poller *poller, const struct timeval *tv)
5061cecc5deSJohnathan Mantey {
5071cecc5deSJohnathan Mantey 	struct timeval now;
5081cecc5deSJohnathan Mantey 	int rc;
5091cecc5deSJohnathan Mantey 
5101cecc5deSJohnathan Mantey 	rc = get_current_time(&now);
5112834c5b1SAndrew Jeffery 	if (rc) {
5121cecc5deSJohnathan Mantey 		return;
5132834c5b1SAndrew Jeffery 	}
5141cecc5deSJohnathan Mantey 
5151cecc5deSJohnathan Mantey 	timeradd(&now, tv, &poller->timeout);
5161cecc5deSJohnathan Mantey }
5171cecc5deSJohnathan Mantey 
5185c359cc6SAndrew Jeffery static long get_poll_timeout(struct console *console, struct timeval *cur_time)
5191cecc5deSJohnathan Mantey {
520b70f8713SAndrew Jeffery 	struct timeval *earliest;
521b70f8713SAndrew Jeffery 	struct timeval interval;
5221cecc5deSJohnathan Mantey 	struct poller *poller;
5231cecc5deSJohnathan Mantey 	int i;
5241cecc5deSJohnathan Mantey 
5251cecc5deSJohnathan Mantey 	earliest = NULL;
5261cecc5deSJohnathan Mantey 
5271cecc5deSJohnathan Mantey 	for (i = 0; i < console->n_pollers; i++) {
5281cecc5deSJohnathan Mantey 		poller = console->pollers[i];
5291cecc5deSJohnathan Mantey 
5301cecc5deSJohnathan Mantey 		if (poller->timeout_fn && timerisset(&poller->timeout) &&
5311cecc5deSJohnathan Mantey 		    (!earliest ||
5321cecc5deSJohnathan Mantey 		     (earliest && timercmp(&poller->timeout, earliest, <)))) {
5331cecc5deSJohnathan Mantey 			// poller is buffering data and needs the poll
5341cecc5deSJohnathan Mantey 			// function to timeout.
5351cecc5deSJohnathan Mantey 			earliest = &poller->timeout;
5361cecc5deSJohnathan Mantey 		}
5371cecc5deSJohnathan Mantey 	}
5381cecc5deSJohnathan Mantey 
5391cecc5deSJohnathan Mantey 	if (earliest) {
5401cecc5deSJohnathan Mantey 		if (timercmp(earliest, cur_time, >)) {
5411cecc5deSJohnathan Mantey 			/* recalculate the timeout period, time period has
5421cecc5deSJohnathan Mantey 			 * not elapsed */
5431cecc5deSJohnathan Mantey 			timersub(earliest, cur_time, &interval);
5441cecc5deSJohnathan Mantey 			return ((interval.tv_sec * 1000) +
5451cecc5deSJohnathan Mantey 				(interval.tv_usec / 1000));
5460b7b0477SAndrew Jeffery 		} /* return from poll immediately */
5471cecc5deSJohnathan Mantey 		return 0;
5480b7b0477SAndrew Jeffery 
5490b7b0477SAndrew Jeffery 	} /* poll indefinitely */
5501cecc5deSJohnathan Mantey 	return -1;
5511cecc5deSJohnathan Mantey }
5521cecc5deSJohnathan Mantey 
5531cecc5deSJohnathan Mantey static int call_pollers(struct console *console, struct timeval *cur_time)
554329a35f5SJeremy Kerr {
555329a35f5SJeremy Kerr 	struct poller *poller;
556329a35f5SJeremy Kerr 	struct pollfd *pollfd;
557329a35f5SJeremy Kerr 	enum poller_ret prc;
558b70f8713SAndrew Jeffery 	int i;
559b70f8713SAndrew Jeffery 	int rc;
560d831f960SJeremy Kerr 
5611a0e03b4SJeremy Kerr 	rc = 0;
5621a0e03b4SJeremy Kerr 
563329a35f5SJeremy Kerr 	/*
564329a35f5SJeremy Kerr 	 * Process poll events by iterating through the pollers and pollfds
565329a35f5SJeremy Kerr 	 * in-step, calling any pollers that we've found revents for.
566329a35f5SJeremy Kerr 	 */
567329a35f5SJeremy Kerr 	for (i = 0; i < console->n_pollers; i++) {
568329a35f5SJeremy Kerr 		poller = console->pollers[i];
569329a35f5SJeremy Kerr 		pollfd = &console->pollfds[i];
5701cecc5deSJohnathan Mantey 		prc = POLLER_OK;
5711a0e03b4SJeremy Kerr 
5721cecc5deSJohnathan Mantey 		/* process pending events... */
5731cecc5deSJohnathan Mantey 		if (pollfd->revents) {
5741cecc5deSJohnathan Mantey 			prc = poller->event_fn(poller->handler, pollfd->revents,
575329a35f5SJeremy Kerr 					       poller->data);
5762834c5b1SAndrew Jeffery 			if (prc == POLLER_EXIT) {
577329a35f5SJeremy Kerr 				rc = -1;
5782834c5b1SAndrew Jeffery 			} else if (prc == POLLER_REMOVE) {
579329a35f5SJeremy Kerr 				poller->remove = true;
580329a35f5SJeremy Kerr 			}
5812834c5b1SAndrew Jeffery 		}
582329a35f5SJeremy Kerr 
5831cecc5deSJohnathan Mantey 		if ((prc == POLLER_OK) && poller->timeout_fn &&
5841cecc5deSJohnathan Mantey 		    timerisset(&poller->timeout) &&
5851cecc5deSJohnathan Mantey 		    timercmp(&poller->timeout, cur_time, <=)) {
5861cecc5deSJohnathan Mantey 			/* One of the ringbuffer consumers is buffering the
5871cecc5deSJohnathan Mantey 			data stream. The amount of idle time the consumer
5881cecc5deSJohnathan Mantey 			desired has expired.  Process the buffered data for
5891cecc5deSJohnathan Mantey 			transmission. */
5901cecc5deSJohnathan Mantey 			timerclear(&poller->timeout);
5911cecc5deSJohnathan Mantey 			prc = poller->timeout_fn(poller->handler, poller->data);
5921cecc5deSJohnathan Mantey 			if (prc == POLLER_EXIT) {
5931cecc5deSJohnathan Mantey 				rc = -1;
5941cecc5deSJohnathan Mantey 			} else if (prc == POLLER_REMOVE) {
5951cecc5deSJohnathan Mantey 				poller->remove = true;
5961cecc5deSJohnathan Mantey 			}
5971cecc5deSJohnathan Mantey 		}
5981cecc5deSJohnathan Mantey 	}
5991cecc5deSJohnathan Mantey 
600329a35f5SJeremy Kerr 	/**
601329a35f5SJeremy Kerr 	 * Process deferred removals; restarting each time we unregister, as
602329a35f5SJeremy Kerr 	 * the array will have changed
603329a35f5SJeremy Kerr 	 */
604329a35f5SJeremy Kerr 	for (;;) {
605329a35f5SJeremy Kerr 		bool removed = false;
606329a35f5SJeremy Kerr 
607329a35f5SJeremy Kerr 		for (i = 0; i < console->n_pollers; i++) {
608329a35f5SJeremy Kerr 			poller = console->pollers[i];
609329a35f5SJeremy Kerr 			if (poller->remove) {
61055c9712dSJeremy Kerr 				console_poller_unregister(console, poller);
611329a35f5SJeremy Kerr 				removed = true;
612329a35f5SJeremy Kerr 				break;
613329a35f5SJeremy Kerr 			}
614329a35f5SJeremy Kerr 		}
6152834c5b1SAndrew Jeffery 		if (!removed) {
616329a35f5SJeremy Kerr 			break;
6171a0e03b4SJeremy Kerr 		}
6182834c5b1SAndrew Jeffery 	}
6191a0e03b4SJeremy Kerr 
6201a0e03b4SJeremy Kerr 	return rc;
6211a0e03b4SJeremy Kerr }
6221a0e03b4SJeremy Kerr 
623769cee1aSJeremy Kerr static void sighandler(int signal)
624769cee1aSJeremy Kerr {
6252834c5b1SAndrew Jeffery 	if (signal == SIGINT) {
626769cee1aSJeremy Kerr 		sigint = true;
627769cee1aSJeremy Kerr 	}
6282834c5b1SAndrew Jeffery }
629769cee1aSJeremy Kerr 
6301a0e03b4SJeremy Kerr int run_console(struct console *console)
6311a0e03b4SJeremy Kerr {
6325c359cc6SAndrew Jeffery 	sighandler_t sighandler_save = signal(SIGINT, sighandler);
6331cecc5deSJohnathan Mantey 	struct timeval tv;
6345c359cc6SAndrew Jeffery 	long timeout;
6355c359cc6SAndrew Jeffery 	ssize_t rc;
636769cee1aSJeremy Kerr 
637769cee1aSJeremy Kerr 	rc = 0;
638769cee1aSJeremy Kerr 
639d831f960SJeremy Kerr 	for (;;) {
640d831f960SJeremy Kerr 		uint8_t buf[4096];
641d831f960SJeremy Kerr 
6421764145dSJeremy Kerr 		BUILD_ASSERT(sizeof(buf) <= buffer_size);
6431764145dSJeremy Kerr 
644769cee1aSJeremy Kerr 		if (sigint) {
645769cee1aSJeremy Kerr 			fprintf(stderr, "Received interrupt, exiting\n");
646769cee1aSJeremy Kerr 			break;
647769cee1aSJeremy Kerr 		}
648769cee1aSJeremy Kerr 
6491cecc5deSJohnathan Mantey 		rc = get_current_time(&tv);
6501cecc5deSJohnathan Mantey 		if (rc) {
6511cecc5deSJohnathan Mantey 			warn("Failed to read current time");
6521cecc5deSJohnathan Mantey 			break;
6531cecc5deSJohnathan Mantey 		}
6541cecc5deSJohnathan Mantey 
6551cecc5deSJohnathan Mantey 		timeout = get_poll_timeout(console, &tv);
6561cecc5deSJohnathan Mantey 
657329a35f5SJeremy Kerr 		rc = poll(console->pollfds,
6585c359cc6SAndrew Jeffery 			  console->n_pollers + MAX_INTERNAL_POLLFD,
6595c359cc6SAndrew Jeffery 			  (int)timeout);
6601cecc5deSJohnathan Mantey 
661d831f960SJeremy Kerr 		if (rc < 0) {
662769cee1aSJeremy Kerr 			if (errno == EINTR) {
663769cee1aSJeremy Kerr 				continue;
6640b7b0477SAndrew Jeffery 			}
665d831f960SJeremy Kerr 			warn("poll error");
666769cee1aSJeremy Kerr 			break;
667769cee1aSJeremy Kerr 		}
668d831f960SJeremy Kerr 
669329a35f5SJeremy Kerr 		/* process internal fd first */
670329a35f5SJeremy Kerr 		if (console->pollfds[console->n_pollers].revents) {
6711a0e03b4SJeremy Kerr 			rc = read(console->tty_fd, buf, sizeof(buf));
672d831f960SJeremy Kerr 			if (rc <= 0) {
673d831f960SJeremy Kerr 				warn("Error reading from tty device");
674769cee1aSJeremy Kerr 				rc = -1;
675769cee1aSJeremy Kerr 				break;
676d831f960SJeremy Kerr 			}
677f733c85aSJeremy Kerr 			rc = ringbuffer_queue(console->rb, buf, rc);
6782834c5b1SAndrew Jeffery 			if (rc) {
679769cee1aSJeremy Kerr 				break;
680d831f960SJeremy Kerr 			}
6812834c5b1SAndrew Jeffery 		}
682d831f960SJeremy Kerr 
683f9c8f6caSCheng C Yang 		if (console->pollfds[console->n_pollers + 1].revents) {
684f9c8f6caSCheng C Yang 			sd_bus_process(console->bus, NULL);
685f9c8f6caSCheng C Yang 		}
686f9c8f6caSCheng C Yang 
687329a35f5SJeremy Kerr 		/* ... and then the pollers */
6881cecc5deSJohnathan Mantey 		rc = call_pollers(console, &tv);
6892834c5b1SAndrew Jeffery 		if (rc) {
690769cee1aSJeremy Kerr 			break;
6911a0e03b4SJeremy Kerr 		}
6922834c5b1SAndrew Jeffery 	}
693769cee1aSJeremy Kerr 
694769cee1aSJeremy Kerr 	signal(SIGINT, sighandler_save);
695f9c8f6caSCheng C Yang 	sd_bus_unref(console->bus);
696769cee1aSJeremy Kerr 
697769cee1aSJeremy Kerr 	return rc ? -1 : 0;
6981a0e03b4SJeremy Kerr }
699d831f960SJeremy Kerr static const struct option options[] = {
700d66195c1SJeremy Kerr 	{ "config", required_argument, 0, 'c' },
701f5858b5bSJoel Stanley 	{ 0, 0, 0, 0 },
702d831f960SJeremy Kerr };
703d831f960SJeremy Kerr 
704d831f960SJeremy Kerr int main(int argc, char **argv)
705d831f960SJeremy Kerr {
706d66195c1SJeremy Kerr 	const char *config_filename = NULL;
7076221ce94SVishwanatha Subbanna 	const char *config_tty_kname = NULL;
7081a0e03b4SJeremy Kerr 	struct console *console;
709d66195c1SJeremy Kerr 	struct config *config;
710d66195c1SJeremy Kerr 	int rc;
711d831f960SJeremy Kerr 
712957818b4SJeremy Kerr 	rc = -1;
713d831f960SJeremy Kerr 
714d831f960SJeremy Kerr 	for (;;) {
715b70f8713SAndrew Jeffery 		int c;
716b70f8713SAndrew Jeffery 		int idx;
717d831f960SJeremy Kerr 
718d66195c1SJeremy Kerr 		c = getopt_long(argc, argv, "c:", options, &idx);
7192834c5b1SAndrew Jeffery 		if (c == -1) {
720d831f960SJeremy Kerr 			break;
7212834c5b1SAndrew Jeffery 		}
722d831f960SJeremy Kerr 
723d831f960SJeremy Kerr 		switch (c) {
724d66195c1SJeremy Kerr 		case 'c':
725d66195c1SJeremy Kerr 			config_filename = optarg;
726d831f960SJeremy Kerr 			break;
727d831f960SJeremy Kerr 		case 'h':
728d831f960SJeremy Kerr 		case '?':
729d831f960SJeremy Kerr 			usage(argv[0]);
730d66195c1SJeremy Kerr 			return EXIT_SUCCESS;
731d831f960SJeremy Kerr 		}
732d831f960SJeremy Kerr 	}
733d831f960SJeremy Kerr 
7342834c5b1SAndrew Jeffery 	if (optind < argc) {
7356221ce94SVishwanatha Subbanna 		config_tty_kname = argv[optind];
7362834c5b1SAndrew Jeffery 	}
7376221ce94SVishwanatha Subbanna 
738d66195c1SJeremy Kerr 	console = malloc(sizeof(struct console));
739d66195c1SJeremy Kerr 	memset(console, 0, sizeof(*console));
740a72711afSAndrew Jeffery 	console->pollfds =
741a72711afSAndrew Jeffery 		calloc(MAX_INTERNAL_POLLFD, sizeof(*console->pollfds));
742f733c85aSJeremy Kerr 	console->rb = ringbuffer_init(buffer_size);
743329a35f5SJeremy Kerr 
744d66195c1SJeremy Kerr 	config = config_init(config_filename);
745d66195c1SJeremy Kerr 	if (!config) {
746d66195c1SJeremy Kerr 		warnx("Can't read configuration, exiting.");
747d66195c1SJeremy Kerr 		goto out_free;
748d831f960SJeremy Kerr 	}
749d831f960SJeremy Kerr 
7502834c5b1SAndrew Jeffery 	if (!config_tty_kname) {
75191dde14eSAndrew Jeffery 		config_tty_kname = config_get_value(config, "upstream-tty");
7522834c5b1SAndrew Jeffery 	}
75391dde14eSAndrew Jeffery 
75491dde14eSAndrew Jeffery 	if (!config_tty_kname) {
75591dde14eSAndrew Jeffery 		warnx("No TTY device specified");
75691dde14eSAndrew Jeffery 		usage(argv[0]);
75791dde14eSAndrew Jeffery 		return EXIT_FAILURE;
75891dde14eSAndrew Jeffery 	}
75991dde14eSAndrew Jeffery 
760*b14ca19cSNinad Palsule 	if (set_socket_info(console, config)) {
761*b14ca19cSNinad Palsule 		return EXIT_FAILURE;
762*b14ca19cSNinad Palsule 	}
763*b14ca19cSNinad Palsule 
7646221ce94SVishwanatha Subbanna 	console->tty_kname = config_tty_kname;
7656221ce94SVishwanatha Subbanna 
7664e718691SNinad Palsule 	console->console_id = config_get_value(config, "socket-id");
7674e718691SNinad Palsule 	if (!console->console_id) {
7684e718691SNinad Palsule 		warnx("Error: The socket-id is not set in the config file");
7694e718691SNinad Palsule 		return EXIT_FAILURE;
7704e718691SNinad Palsule 	}
7714e718691SNinad Palsule 
772d66195c1SJeremy Kerr 	rc = tty_init(console, config);
7732834c5b1SAndrew Jeffery 	if (rc) {
774d66195c1SJeremy Kerr 		goto out_config_fini;
7752834c5b1SAndrew Jeffery 	}
776d831f960SJeremy Kerr 
777f9c8f6caSCheng C Yang 	dbus_init(console, config);
778f9c8f6caSCheng C Yang 
779d47963e5SJeremy Kerr 	handlers_init(console, config);
780d831f960SJeremy Kerr 
7811a0e03b4SJeremy Kerr 	rc = run_console(console);
782d831f960SJeremy Kerr 
7831a0e03b4SJeremy Kerr 	handlers_fini(console);
784d831f960SJeremy Kerr 
785d66195c1SJeremy Kerr out_config_fini:
786d66195c1SJeremy Kerr 	config_fini(config);
787d66195c1SJeremy Kerr 
788957818b4SJeremy Kerr out_free:
78989ea8198SJeremy Kerr 	free(console->pollers);
79089ea8198SJeremy Kerr 	free(console->pollfds);
7911a0e03b4SJeremy Kerr 	free(console->tty_sysfs_devnode);
7921a0e03b4SJeremy Kerr 	free(console->tty_dev);
7931a0e03b4SJeremy Kerr 	free(console);
794d831f960SJeremy Kerr 
795d831f960SJeremy Kerr 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;
796d831f960SJeremy Kerr }
797