Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email )
Change subject: util: Make m5term able to connect to unix domain sockets.
......................................................................
util: Make m5term able to connect to unix domain sockets.
To connect to a unix domain socket, it must start with a non-digit
character to avoid being confused with a TCP port. If it starts with an
"@" character, then it is treated as an abstract socket.
Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09
---
M util/term/term.c
1 file changed, 117 insertions(+), 29 deletions(-)
diff --git a/util/term/term.c b/util/term/term.c
index 529712c..8cbd202 100644
--- a/util/term/term.c
+++ b/util/term/term.c
@@ -27,26 +27,30 @@
*/
#include <arpa/telnet.h>
-#include <netinet/in.h>
-#include <sys/socket.h>
-#include <sys/termios.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/un.h>
+#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
+#include <linux/limits.h>
#include <netdb.h>
+#include <netinet/in.h>
#include <poll.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
+#include <sys/termios.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/un.h>
#include <unistd.h>
ssize_t atomicio(ssize_t (*)(), int, void *, size_t);
void readwrite(int);
-int remote_connect(char *, char *, struct addrinfo);
+int remote_connect_inet(char *, char *);
+int remote_connect_unix(char *);
struct termios saved_ios;
void raw_term();
@@ -60,7 +64,6 @@
{
int ch, s, ret;
char *host, *port, *endp;
- struct addrinfo hints;
socklen_t len;
ret = 1;
@@ -87,33 +90,40 @@
raw_term();
+ if (isdigit(port[0])) {
+ s = remote_connect_inet(host, port);
+ } else {
+ if (argc != 2)
+ errx(1, "host specified with local socket");
+ s = remote_connect_unix(port);
+ }
+
+ if (s != -1) {
+ readwrite(s);
+ close(s);
+ }
+
+ exit(0);
+}
+
+/*
+ * remote_connect_inet()
+ * Return's a socket connected to a remote host. Properly bind's to a local
+ * port or source address if needed. Return's -1 on failure.
+ */
+int
+remote_connect_inet(char *host, char *port)
+{
+ struct addrinfo hints;
+ struct addrinfo *res, *res0;
+ int s, error;
+
/* Initialize addrinfo structure */
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
- s = remote_connect(host, port, hints);
- ret = 0;
- readwrite(s);
-
- if (s)
- close(s);
-
- exit(ret);
-}
-
-/*
- * remote_connect()
- * Return's a socket connected to a remote host. Properly bind's to a local
- * port or source address if needed. Return's -1 on failure.
- */
-int
-remote_connect(char *host, char *port, struct addrinfo hints)
-{
- struct addrinfo *res, *res0;
- int s, error;
-
if ((error = getaddrinfo(host, port, &hints, &res)))
errx(1, "getaddrinfo: %s", gai_strerror(error));
@@ -136,6 +146,84 @@
}
/*
+ * remote_connect_inet()
+ * Return's a socket connected to a remote host. Properly bind's to a local
+ * port or source address if needed. Return's -1 on failure.
+ */
+int
+remote_connect_unix(char *path)
+{
+ struct sockaddr_un addr;
+
+ // Create a copy of path so we can safely modify it in place.
+ char *pathc = strdup(path);
+ path = pathc;
+
+ // Create a unix domain socket.
+ int s = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (s == -1)
+ return s;
+
+ // Prepare the scokaddr_un.
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+
+ // Keep track of where we're filling in the path, and the remaining
space.
+ int path_size = sizeof(addr.sun_path);
+ char *sun_path = &addr.sun_path[0];
+
+ // Keep track of the current directory in case we change it to maximize
+ // what we can fit in the limited space in sun_path.
+ char *cwd = NULL;
+
+ if (path[0] == '@') {
+ // If this is an abstract socket, prefix it with a null byte.
+ *sun_path++ = '\0';
+ path++;
+ path_size--;
+ // Keep track of how much of sun_path is actual data since
everything
+ // we include will be part of the lookup.
+ int len = strlen(path);
+ if (len < path_size)
+ path_size = len;
+ } else {
+ // Switch to the parent directory of the socket.
+ cwd = (char *)malloc(PATH_MAX);
+ getcwd(cwd, PATH_MAX);
+ char *dirc = strdup(path);
+ char *dname = dirname(dirc);
+ chdir(dname);
+ free(dirc);
+
+ // Replace the path with just the filename part. We still have a
+ // pointer to our copy of "path" so we can clean it up later.
+ path = basename(path);
+ }
+
+ // Copy the path into sun_path.
+ strncpy(sun_path, path, path_size);
+
+ // Figure out how much actual data we have in sockaddr_un.
+ int struct_len = (char *)sun_path + path_size - (char *)&addr;
+
+ // Actually connect to the socket.
+ if (connect(s, (struct sockaddr *)&addr, struct_len) == -1) {
+ // If that didn't work, switch our dir back and error out.
+ if (cwd)
+ chdir(cwd);
+ errx(1, "Failed to connect");
+ }
+
+ // We're connected, clean up memory and switch the current dir back.
+ free(pathc);
+ if (cwd)
+ chdir(cwd);
+
+ // Return the FD of our new connection.
+ return s;
+}
+
+/*
* readwrite()
* Loop that selects on the network file descriptor and stdin.
* Changed from poll() by Ali Saidi to make work on Mac OS X >= 10.4
--
To view, visit
https://gem5-review.googlesource.com/c/public/gem5/+/69167?usp=email
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I3a71eb8ef80018546f3bbf9d781770bd37ecec09
Gerrit-Change-Number: 69167
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <gabe.bl...@gmail.com>
Gerrit-CC: Gabe Black <gabebl...@google.com>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list -- gem5-dev@gem5.org
To unsubscribe send an email to gem5-dev-le...@gem5.org