console-server: Specify devices by kernel names

This change adds a little lookup code to find the device path in sysfs,
so changing the --device syntax to give just the raw kname (ie, without
the /dev/ prefix).

We'll use this later to interact with the extended properties of a
VUART.

Signed-off-by: Jeremy Kerr <jk@ozlabs.org>
diff --git a/console-server.c b/console-server.c
index de6a34a..005af60 100644
--- a/console-server.c
+++ b/console-server.c
@@ -4,6 +4,8 @@
  * Copyright © 2016 IBM Corporation <jk@ozlabs.org>
  */
 
+#define _GNU_SOURCE
+
 #include <stdint.h>
 #include <stdbool.h>
 #include <stdlib.h>
@@ -14,6 +16,7 @@
 #include <termios.h>
 #include <string.h>
 #include <getopt.h>
+#include <limits.h>
 
 #include <sys/types.h>
 #include <sys/poll.h>
@@ -23,7 +26,9 @@
 static const char esc_str[] = { '\r', '~', '.' };
 
 struct console_ctx {
-	const char	*tty_dev;
+	const char	*tty_kname;
+	char		*tty_sysfs_devnode;
+	char		*tty_dev;
 	int		tty_fd;
 	int		console_fd_in;
 	int		console_fd_out;
@@ -38,16 +43,65 @@
 "usage: %s [options]\n"
 "\n"
 "Options:\n"
-"  --device <TTY>  Use serial device TTY\n"
+"  --device <TTY>  Use serial device TTY (eg, ttyS0)\n"
 "",
 		progname);
 }
 
+/* populates tty_dev and tty_sysfs_devnode, using the tty kernel name */
+static int tty_find_device(struct console_ctx *ctx)
+{
+	char *tty_class_device_link;
+	char *tty_device_tty_dir;
+	char *tty_device_reldir;
+	int rc;
+
+	rc = -1;
+	tty_class_device_link = NULL;
+	tty_device_tty_dir = NULL;
+	tty_device_reldir = NULL;
+
+	rc = asprintf(&tty_class_device_link,
+			"/sys/class/tty/%s", ctx->tty_kname);
+	if (rc < 0)
+		return -1;
+
+	tty_device_tty_dir = realpath(tty_class_device_link, NULL);
+	if (rc < 0) {
+		warn("Can't query sysfs for device %s", ctx->tty_kname);
+		goto out_free;
+	}
+
+	rc = asprintf(&tty_device_reldir, "%s/../../", tty_device_tty_dir);
+	if (rc < 0)
+		goto out_free;
+
+	ctx->tty_sysfs_devnode = realpath(tty_device_reldir, NULL);
+	if (!ctx->tty_sysfs_devnode)
+		warn("Can't find parent device for %s", ctx->tty_kname);
+
+
+	/* todo: lookup from major/minor info in sysfs, in case udev has
+	 * renamed us */
+	rc = asprintf(&ctx->tty_dev, "/dev/%s", ctx->tty_kname);
+	if (rc < 0)
+		goto out_free;
+
+	rc = 0;
+
+out_free:
+	free(tty_class_device_link);
+	free(tty_device_tty_dir);
+	free(tty_device_reldir);
+	return rc;
+}
+
 /**
  * Open and initialise the serial device
  */
 static int tty_init_io(struct console_ctx *ctx)
 {
+
 	ctx->tty_fd = open(ctx->tty_dev, O_RDWR);
 	if (ctx->tty_fd <= 0) {
 		warn("Can't open tty %s", ctx->tty_dev);
@@ -212,7 +266,7 @@
 
 		switch (c) {
 		case 'd':
-			ctx->tty_dev = optarg;
+			ctx->tty_kname = optarg;
 			break;
 
 		case 'h':
@@ -222,12 +276,18 @@
 		}
 	}
 
-	if (!ctx->tty_dev) {
+	if (!ctx->tty_kname) {
 		fprintf(stderr,
 			"Error: No TTY device specified (use --device)\n");
 		return EXIT_FAILURE;
 	}
 
+	rc = tty_find_device(ctx);
+	if (rc)
+		return EXIT_FAILURE;
+
+	return EXIT_SUCCESS;
+
 	rc = tty_init_io(ctx);
 	if (rc)
 		return EXIT_FAILURE;
@@ -240,6 +300,8 @@
 
 	console_restore_termios(ctx);
 
+	free(ctx->tty_sysfs_devnode);
+	free(ctx->tty_dev);
 	free(ctx);
 
 	return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE;