console-socket: Add an optional component to UNIX socket abstract names

Allows multiple instances of obmc-console-server to run concurrently
without interfering with each other.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Change-Id: I7ef9c14e554c687e8d606e1eaaed82a7f1c06d98
diff --git a/console-client.c b/console-client.c
index 052ece2..af1094f 100644
--- a/console-client.c
+++ b/console-client.c
@@ -15,6 +15,7 @@
  */
 
 #include <err.h>
+#include <errno.h>
 #include <getopt.h>
 #include <stdbool.h>
 #include <stdint.h>
@@ -209,6 +210,7 @@
 static int client_init(struct console_client *client)
 {
 	struct sockaddr_un addr;
+	ssize_t len;
 	int rc;
 
 	client->console_sd = socket(AF_UNIX, SOCK_STREAM, 0);
@@ -219,17 +221,24 @@
 
 	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
-	memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
-
-	rc = connect(client->console_sd, (struct sockaddr *)&addr,
-			sizeof(addr) - sizeof(addr.sun_path) + console_socket_path_len);
-	if (rc) {
-		warn("Can't connect to console server");
-		close(client->console_sd);
-		return -1;
+	len = console_socket_path(&addr, NULL);
+	if (len < 0) {
+		if (errno)
+			warn("Failed to configure socket: %s", strerror(errno));
+		else
+			warn("Socket name length exceeds buffer limits");
+		goto cleanup;
 	}
 
-	return 0;
+	rc = connect(client->console_sd, (struct sockaddr *)&addr,
+			sizeof(addr) - sizeof(addr.sun_path) + len);
+	if (!rc)
+		return 0;
+
+	warn("Can't connect to console server");
+cleanup:
+	close(client->console_sd);
+	return -1;
 }
 
 static void client_fini(struct console_client *client)
diff --git a/console-server.h b/console-server.h
index d6822c5..b6ab1b8 100644
--- a/console-server.h
+++ b/console-server.h
@@ -23,6 +23,7 @@
 #include <time.h>
 #include <systemd/sd-bus.h>
 #include <sys/time.h>
+#include <sys/un.h>
 
 struct console;
 struct config;
@@ -138,9 +139,11 @@
 int config_parse_logsize(const char *size_str, size_t *size);
 
 /* socket paths */
-extern const char *console_socket_path;
-extern const size_t console_socket_path_len;
-extern const char *console_socket_path_readable;
+ssize_t console_socket_path(struct sockaddr_un *addr, const char *id);
+
+typedef char (socket_path_t)[sizeof(((struct sockaddr_un *)NULL)->sun_path)];
+ssize_t console_socket_path_readable(const struct sockaddr_un *addr,
+				     size_t addrlen, socket_path_t path);
 
 /* utils */
 int write_buf_to_fd(int fd, const uint8_t *buf, size_t len);
diff --git a/console-socket.c b/console-socket.c
index 9e1cf30..b0cd452 100644
--- a/console-socket.c
+++ b/console-socket.c
@@ -14,9 +14,53 @@
  * limitations under the License.
  */
 
+#include "console-server.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/types.h>
 
-const char console_socket_path[] = "\0obmc-console";
-const size_t console_socket_path_len = sizeof(console_socket_path) - 1;
-const char *console_socket_path_readable = console_socket_path + 1;
+#define CONSOLE_SOCKET_PREFIX "obmc-console"
 
+ssize_t console_socket_path(struct sockaddr_un *addr, const char *id)
+{
+	char *sun_path;
+	ssize_t rc;
+
+	sun_path = (char *)addr + sizeof(*addr) - sizeof(addr->sun_path);
+
+	if (id) {
+		rc = snprintf(sun_path + 1, sizeof(addr->sun_path) - 1,
+			      CONSOLE_SOCKET_PREFIX ".%s", id);
+	} else {
+		rc = snprintf(sun_path + 1, sizeof(addr->sun_path) - 1,
+			      CONSOLE_SOCKET_PREFIX);
+	}
+
+	if (rc < 0)
+		return rc;
+
+	if (rc > (sizeof(addr->sun_path) - 1)) {
+		errno = 0;
+		return -1;
+	}
+
+	sun_path[0] = '\0';
+
+	return rc + 1 /* Capture NUL prefix */;
+}
+
+ssize_t console_socket_path_readable(const struct sockaddr_un *addr,
+				     size_t addrlen, socket_path_t path)
+{
+	const char *src = (const char *)addr;
+	const size_t len = addrlen - sizeof(addr->sun_family) - 1;
+
+	memcpy(path, src + sizeof(addr->sun_family) + 1, len);
+	path[len] = '\0';
+
+	return len; /* strlen() style */
+}
diff --git a/socket-handler.c b/socket-handler.c
index be7daa4..00044f4 100644
--- a/socket-handler.c
+++ b/socket-handler.c
@@ -306,6 +306,8 @@
 {
 	struct socket_handler *sh = to_socket_handler(handler);
 	struct sockaddr_un addr;
+	size_t addrlen;
+	ssize_t len;
 	int rc;
 
 	sh->console = console;
@@ -320,26 +322,39 @@
 
 	memset(&addr, 0, sizeof(addr));
 	addr.sun_family = AF_UNIX;
-	memcpy(&addr.sun_path, &console_socket_path, console_socket_path_len);
+	len = console_socket_path(&addr, NULL);
+	if (len < 0) {
+		if (errno)
+			warn("Failed to configure socket: %s", strerror(errno));
+		else
+			warn("Socket name length exceeds buffer limits");
+		goto cleanup;
+	}
 
-	rc = bind(sh->sd, (struct sockaddr *)&addr,
-			sizeof(addr) - sizeof(addr.sun_path) + console_socket_path_len);
+	addrlen = sizeof(addr) - sizeof(addr.sun_path) + len;
+
+	rc = bind(sh->sd, (struct sockaddr *)&addr, addrlen);
 	if (rc) {
-		warn("Can't bind to socket path %s",
-				console_socket_path_readable);
-		return -1;
+		socket_path_t name;
+		console_socket_path_readable(&addr, addrlen, name);
+		warn("Can't bind to socket path %s (terminated at first null)",
+				name);
+		goto cleanup;
 	}
 
 	rc = listen(sh->sd, 1);
 	if (rc) {
 		warn("Can't listen for incoming connections");
-		return -1;
+		goto cleanup;
 	}
 
 	sh->poller = console_poller_register(console, handler, socket_poll,
 			NULL, sh->sd, POLLIN, NULL);
 
 	return 0;
+cleanup:
+	close(sh->sd);
+	return -1;
 }
 
 static void socket_fini(struct handler *handler)
diff --git a/test/test-client-escape.c b/test/test-client-escape.c
index 76e9c15..eeae015 100644
--- a/test/test-client-escape.c
+++ b/test/test-client-escape.c
@@ -18,11 +18,12 @@
 #include <stdint.h>
 #include <stdio.h>
 
-#define main __main
 #define read __read
+#include "console-socket.c"
+#define main __main
 #include "console-client.c"
-#undef main
 #undef read
+#undef main
 
 struct test {
 	enum esc_type	esc_type;
@@ -153,11 +154,6 @@
 
 struct test_ctx ctxs[ARRAY_SIZE(tests)];
 
-/* stubs for console socket */
-const char *console_socket_path = "";
-const size_t console_socket_path_len = 1;
-const char *console_socket_path_readable = 0;
-
 int write_buf_to_fd(int fd, const uint8_t *buf, size_t len)
 {
 	struct test_ctx *ctx = &ctxs[fd];