Allow sockets to use longer paths on macOS

This commit is contained in:
Bo Anderson 2024-09-27 02:50:37 +01:00
parent 326a71712f
commit 567f5eb4be
No known key found for this signature in database
7 changed files with 99 additions and 8 deletions

View File

@ -13,7 +13,7 @@ require "build_options"
require "keg"
require "extend/ENV"
require "fcntl"
require "socket"
require "utils/socket"
require "cmd/install"
require "json/add/exception"
@ -221,7 +221,7 @@ begin
args = Homebrew::Cmd::InstallCmd.new.args
Context.current = args.context
error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap)

View File

@ -0,0 +1,30 @@
# typed: strict
# frozen_string_literal: true
require "socket"
module OS
module Mac
# Wrapper around UNIXSocket to allow > 104 characters on macOS.
module UNIXSocketExt
extend T::Helpers
requires_ancestor { Kernel }
sig { params(path: String).returns(String) }
def sockaddr_un(path)
if path.bytesize > 252 # largest size that can fit into a single-byte length
raise ArgumentError, "too long unix socket path (#{path.bytesize} bytes given but 252 bytes max)"
end
[
path.bytesize + 3, # = length (1 byte) + family (1 byte) + path (variable) + null terminator (1 byte)
1, # AF_UNIX
path,
].pack("CCZ*")
end
end
end
end
Utils::UNIXSocketExt.singleton_class.prepend(OS::Mac::UNIXSocketExt)

View File

@ -0,0 +1,4 @@
# typed: strict
# frozen_string_literal: true
require "extend/os/mac/utils/socket" if OS.mac?

View File

@ -8,7 +8,7 @@ old_trap = trap("INT") { exit! 130 }
require_relative "global"
require "fcntl"
require "socket"
require "utils/socket"
require "cli/parser"
require "cmd/postinstall"
require "json/add/exception"
@ -16,7 +16,7 @@ require "json/add/exception"
begin
ENV.delete("HOMEBREW_FORBID_PACKAGES_FROM_PATHS")
args = Homebrew::Cmd::Postinstall.new.args
error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap)

View File

@ -11,7 +11,7 @@ require "timeout"
require "formula_assertions"
require "formula_free_port"
require "fcntl"
require "socket"
require "utils/socket"
require "cli/parser"
require "dev-cmd/test"
require "json/add/exception"
@ -23,7 +23,7 @@ begin
args = Homebrew::DevCmd::Test.new.args
Context.current = args.context
error_pipe = UNIXSocket.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe = Utils::UNIXSocketExt.open(ENV.fetch("HOMEBREW_ERROR_PIPE"), &:recv_io)
error_pipe.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
trap("INT", old_trap)

View File

@ -2,7 +2,7 @@
# frozen_string_literal: true
require "fcntl"
require "socket"
require "utils/socket"
module Utils
def self.rewrite_child_error(child_error)
@ -37,7 +37,7 @@ module Utils
require "json/add/exception"
block = proc do |tmpdir|
UNIXServer.open("#{tmpdir}/socket") do |server|
UNIXServerExt.open("#{tmpdir}/socket") do |server|
read, write = IO.pipe
pid = fork do

View File

@ -0,0 +1,57 @@
# typed: strict
# frozen_string_literal: true
require "socket"
module Utils
# Wrapper around UNIXSocket to allow > 104 characters on macOS.
module UNIXSocketExt
extend T::Generic
sig {
type_parameters(:U).params(
path: String,
_block: T.proc.params(arg0: UNIXSocket).returns(T.type_parameter(:U)),
).returns(T.type_parameter(:U))
}
def self.open(path, &_block)
socket = Socket.new(:UNIX, :STREAM)
socket.connect(sockaddr_un(path))
unix_socket = UNIXSocket.for_fd(socket.fileno)
socket.autoclose = false # Transfer autoclose responsibility to UNIXSocket
yield unix_socket
end
sig { params(path: String).returns(String) }
def self.sockaddr_un(path)
Socket.sockaddr_un(path)
end
end
# Wrapper around UNIXServer to allow > 104 characters on macOS.
class UNIXServerExt < Socket
extend T::Generic
Elem = type_member(:out) { { fixed: String } }
sig { returns(String) }
attr_reader :path
sig { params(path: String).void }
def initialize(path)
super(:UNIX, :STREAM)
bind(UNIXSocketExt.sockaddr_un(path))
listen(Socket::SOMAXCONN)
@path = path
end
sig { returns(UNIXSocket) }
def accept_nonblock
socket, = super
socket.autoclose = false # Transfer autoclose responsibility to UNIXSocket
UNIXSocket.for_fd(socket.fileno)
end
end
end
require "extend/os/utils/socket"