diff --git a/lib/libc/sys/bind.2 b/lib/libc/sys/bind.2 --- a/lib/libc/sys/bind.2 +++ b/lib/libc/sys/bind.2 @@ -128,6 +128,17 @@ The name would reside on a read-only file system. .It Bq Er EISDIR An empty pathname was specified. +.It Bq Er EEXIST +The specified address (socket path) exists as a socket file but isn't linked +to an alive socket (which means it is a stale socket file). This error code +is non-POSIX and disabled by default. Traditional behaviour is to return +.Er EADDRNOTAVAIL here. See +.Xr unix 4 . +.It Bq Er EFTYPE +The specified address (socket path) exists as a non-socket file. This error +code is non-POSIX and disabled by default. Traditional behaviour is to return +.Er EADDRNOTAVAIL here. See +.Xr unix 4 . .El .Sh SEE ALSO .Xr connect 2 , diff --git a/share/man/man4/unix.4 b/share/man/man4/unix.4 --- a/share/man/man4/unix.4 +++ b/share/man/man4/unix.4 @@ -119,6 +119,22 @@ or .Xr sendto 2 must be writable. +.Pp +The stale socket file which was not removed after socket close will cause +the next +.Xr bind 2 +call with this path to fail. The traditional behaviour is to set +.Va errno +to +.Er EADDRNOTAVAIL +when the specified path already exists, regardless of what exactly exists at +the specified path. However, when +.Va net.local.bind_exist_errext +set to non-zero, the error code will be more detailed: +.Er EADDRNOTAVAIL when the existing socket file actually bound to an existing +socket, +.Er EEXIST when the existing socket file is stale and +.Er EFTYPE when the existing file is not a socket at all. .Sh CONTROL MESSAGES The .Ux Ns -domain diff --git a/sys/kern/uipc_usrreq.c b/sys/kern/uipc_usrreq.c --- a/sys/kern/uipc_usrreq.c +++ b/sys/kern/uipc_usrreq.c @@ -158,6 +158,7 @@ static u_long unpdg_recvspace = 16*1024; /* support 8KB syslog msgs */ static u_long unpsp_sendspace = PIPSIZ; /* really max datagram size */ static u_long unpsp_recvspace = PIPSIZ; +static int bind_exist_errext = 0; static SYSCTL_NODE(_net, PF_LOCAL, local, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, "Local domain"); @@ -183,6 +184,9 @@ &unpsp_sendspace, 0, "Default seqpacket send space."); SYSCTL_ULONG(_net_local_seqpacket, OID_AUTO, recvspace, CTLFLAG_RW, &unpsp_recvspace, 0, "Default seqpacket receive space."); +SYSCTL_INT(_net_local, OID_AUTO, bind_exist_errext, CTLFLAG_RW, + &bind_exist_errext, 0, + "bind() will report EEXIST/EFTYPE for non-bound-socket existing files."); SYSCTL_INT(_net_local, OID_AUTO, inflight, CTLFLAG_RD, &unp_rights, 0, "File descriptors in flight."); SYSCTL_INT(_net_local, OID_AUTO, deferred, CTLFLAG_RD, @@ -607,8 +611,19 @@ else vput(nd.ni_dvp); if (vp != NULL) { + if (bind_exist_errext == 0) + error = EADDRINUSE; + else if (vp->v_type != VSOCK) + error = EFTYPE; + else { + vn_lock(vp, LK_SHARED); + if (vp->v_unpcb == NULL) + error = EEXIST; + else + error = EADDRINUSE; + VOP_UNLOCK(vp, 0); + } vrele(vp); - error = EADDRINUSE; goto error; } error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH);