Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
PATCH: socket: unmetafy the socket name
- X-seq: zsh-workers 55126
- From: Mikael Magnusson <mikachu@xxxxxxxxx>
- To: zsh-workers@xxxxxxx
- Subject: PATCH: socket: unmetafy the socket name
- Date: Thu, 27 Aug 2026 16:28:48 +0200
- Archived-at: <https://zsh.org/workers/55126>
- List-id: <zsh-workers.zsh.org>
This also led me to discover that if you type a leading nul in zsh, it
passes through unscathed on linux and gives us an abstract socket
instead, so document that that works, and print them properly. Also add
support for reporting the autobind socket name if you pass an empty
path.
The more specific size in the bind and connect calls is due to abstract
sockets using the entire specified length, regardless of any embedded 0
bytes.
---
Despite messing around in the socket module quite a bit recently
(54493, 54494, 54986), and fixing metafy confusion in other places
(54600, 54598, 54564, 54557, 52526), I apparently never tested
multibyte paths or noticed the missing unmetafy call in this particular
module. Neat.
Doc/Zsh/mod_socket.yo | 6 +++++
Src/Modules/socket.c | 58 +++++++++++++++++++++++++++++++++----------
2 files changed, 51 insertions(+), 13 deletions(-)
diff --git a/Doc/Zsh/mod_socket.yo b/Doc/Zsh/mod_socket.yo
index 2c699b1d12..c74c91e976 100644
--- a/Doc/Zsh/mod_socket.yo
+++ b/Doc/Zsh/mod_socket.yo
@@ -10,6 +10,12 @@ cindex(sockets, Unix domain)
item(tt(zsocket) [ tt(-alstv) ] [ tt(-d) var(fd) ] [ var(args) ])(
tt(zsocket) is implemented as a builtin to allow full use of shell
command line editing, file I/O, and job control mechanisms.
+
+In the invocations below, var(filename) may start with a NUL byte to use
+the abstract socket namespace where no actual socket file is used. It
+can also be passed as an empty string to ask the kernel to autoassign a
+name, in which case that name will be returned in tt(REPLY2) and printed
+when using the tt(-v) option. This feature may be limited to Linux.
)
enditem()
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c
index 95235453e4..86740fafad 100644
--- a/Src/Modules/socket.c
+++ b/Src/Modules/socket.c
@@ -82,16 +82,19 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
if (OPT_ISSET(ops,'l')) {
- char *localfn;
+ char *sockname;
+ ZSOCKLEN_T addrlen;
+ int socknamelen, abstract;
if (!args[0]) {
zwarnnam(nam, "-l requires an argument");
return 1;
}
- localfn = args[0];
- if (strlen(localfn) >= sizeof(soun.sun_path)) {
- zwarnnam(nam, "socket path too long: %d > %d", strlen(localfn), sizeof(soun.sun_path) -1 );
+ sockname = unmetafy(args[0], &socknamelen);
+ abstract = (sockname[0] == '\0');
+ if (socknamelen > sizeof(soun.sun_path) - !abstract) {
+ zwarnnam(nam, "socket path too long: %d > %d", socknamelen, sizeof(soun.sun_path) - !abstract);
return 1;
}
@@ -103,11 +106,12 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
soun.sun_family = AF_UNIX;
- strncpy(soun.sun_path, localfn, sizeof(soun.sun_path)-1);
+ memcpy(soun.sun_path, sockname, socknamelen);
+ addrlen = offsetof(struct sockaddr_un, sun_path) + socknamelen;
- if (bind(sfd, (struct sockaddr *)&soun, sizeof(struct sockaddr_un)))
+ if (bind(sfd, (struct sockaddr *)&soun, addrlen))
{
- zwarnnam(nam, "could not bind to %s: %e", soun.sun_path, errno);
+ zwarnnam(nam, "could not bind to %s: %e", args[0], errno);
close(sfd);
return 1;
}
@@ -138,9 +142,30 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
fdtable[sfd] = FDT_EXTERNAL;
setiparam_no_convert("REPLY", (zlong)sfd);
+ if (socknamelen == 0) {
+ addrlen = sizeof(soun);
+ if (getsockname(sfd, (struct sockaddr *)&soun, &addrlen) == -1) {
+ zwarnnam(nam, "could not retrieve autobind socket name: %e", errno);
+ return 1;
+ }
+ socknamelen = addrlen - offsetof(struct sockaddr_un, sun_path);
+ if (socknamelen > sizeof(soun.sun_path)) {
+ /* this should not be possible */
+ zwarnnam(nam, "socket name buffer too small, needed %d", socknamelen);
+ return 1;
+ }
+ setsparam("REPLY2", metafy(soun.sun_path, socknamelen, META_DUP));
+ }
- if (verbose)
- printf("%s listener is on fd %d\n", soun.sun_path, sfd);
+ if (verbose) {
+ if (abstract) {
+ /* this seems nicer than just printing ^@ */
+ fputs("abstract:", stdout);
+ }
+ sockname = metafy(soun.sun_path + abstract, socknamelen - abstract, META_STATIC);
+ nicezputs(sockname, stdout);
+ printf(" listener is on fd %d\n", sfd);
+ }
return 0;
@@ -242,13 +267,19 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
else
{
+ char *sockname;
+ ZSOCKLEN_T addrlen;
+ int socknamelen, abstract;
+
if (!args[0]) {
zwarnnam(nam, "zsocket requires an argument");
return 1;
}
- if (strlen(args[0]) >= sizeof(soun.sun_path)) {
- zwarnnam(nam, "socket path too long: %d > %d", strlen(args[0]), sizeof(soun.sun_path) -1 );
+ sockname = unmetafy(args[0], &socknamelen);
+ abstract = (sockname[0] == '\0');
+ if (socknamelen > sizeof(soun.sun_path) - !abstract) {
+ zwarnnam(nam, "socket path too long: %d > %d", socknamelen, sizeof(soun.sun_path) - !abstract);
return 1;
}
@@ -260,9 +291,10 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
}
soun.sun_family = AF_UNIX;
- strncpy(soun.sun_path, args[0], sizeof(soun.sun_path)-1);
+ memcpy(soun.sun_path, sockname, socknamelen);
+ addrlen = offsetof(struct sockaddr_un, sun_path) + socknamelen;
- if (connect(sfd, (struct sockaddr *)&soun, sizeof(struct sockaddr_un))) {
+ if (connect(sfd, (struct sockaddr *)&soun, addrlen)) {
zwarnnam(nam, "connection failed: %e", errno);
close(sfd);
return 1;
--
2.38.1
Messages sorted by:
Reverse Date,
Date,
Thread,
Author