summaryrefslogtreecommitdiffstats
path: root/Src/Modules
diff options
context:
space:
mode:
authorMikael Magnusson <mikachu@gmail.com>2026-08-27 15:14:00 +0200
committerMikael Magnusson <mikachu@gmail.com>2026-09-01 07:22:46 +0200
commit60aaf9c8e0180c740d39bdb7f93d53db638c6721 (patch)
treeb7c484c07ec65baaf4cb5881305a50e34545a5d9 /Src/Modules
parentunposted: ChangeLog for preceding commit (diff)
downloadzsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar.gz
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar.bz2
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar.lz
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar.xz
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.tar.zst
zsh-60aaf9c8e0180c740d39bdb7f93d53db638c6721.zip
55128: socket: unmetafy the socket name
This also led me to discover that if you type a leading nul in zsh, it passes through correctly to linux and it 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.
Diffstat (limited to 'Src/Modules')
-rw-r--r--Src/Modules/socket.c66
1 files changed, 52 insertions, 14 deletions
diff --git a/Src/Modules/socket.c b/Src/Modules/socket.c
index 95235453e..9a415e2d1 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, **reply_arr, buf[DIGBUFSIZE];
+ 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", metafy(sockname, socknamelen, META_STATIC), errno);
close(sfd);
return 1;
}
@@ -137,10 +141,37 @@ bin_zsocket(char *nam, char **args, Options ops, UNUSED(int func))
/* allow to be closed explicitly */
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;
+ }
+ }
- if (verbose)
- printf("%s listener is on fd %d\n", soun.sun_path, sfd);
+ reply_arr = (char **) zalloc(3 * sizeof(char *));
+ convbase(buf, sfd, 10);
+ setsparam("REPLY", ztrdup(buf));
+ reply_arr[0] = ztrdup(buf);
+ reply_arr[1] = metafy(soun.sun_path, socknamelen, META_DUP);
+ reply_arr[2] = NULL;
+ setaparam("reply", reply_arr);
+
+ 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 +273,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 +297,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;