Skip to content

Commit

Permalink
os/linux/ld: add functions for querying dynamic linker
Browse files Browse the repository at this point in the history
  • Loading branch information
alebcay committed Apr 8, 2024
1 parent 5977a0b commit 8b31fcc
Show file tree
Hide file tree
Showing 3 changed files with 131 additions and 0 deletions.
75 changes: 75 additions & 0 deletions Library/Homebrew/os/linux/ld.rb
@@ -0,0 +1,75 @@
# typed: true
# frozen_string_literal: true

module OS
module Linux
# Helper functions for querying `ld` information.
#
# @api private
module Ld
module_function

sig { returns(String) }
def brewed_ld_so_diagnostics
brewed_ld_so = HOMEBREW_PREFIX/"lib/ld.so"
return "" unless brewed_ld_so.exist?

ld_so_output = Utils.popen_read(brewed_ld_so, "--list-diagnostics")
return "" unless $CHILD_STATUS.success?

ld_so_output
end

sig { returns(String) }
def sysconfdir
fallback_sysconfdir = "/etc"

match = brewed_ld_so_diagnostics.match(/path.sysconfdir="(.+)"/)
return fallback_sysconfdir unless match

match.captures.compact.first || fallback_sysconfdir
end

sig { returns(T::Array[String]) }
def system_dirs
dirs = []

brewed_ld_so_diagnostics.split("\n").each do |line|
match = line.match(/path.system_dirs\[0x.*\]="(.*)"/)
next unless match

dirs << match.captures.compact.first
end

dirs
end

def library_paths(conf_path = Pathname(sysconfdir)/"ld.so.conf")
conf_file = Pathname(conf_path)
paths = Set.new
directory = conf_file.realpath.dirname

conf_file.readlines.each do |line|
# Remove comments and leading/trailing whitespace
line.strip!
line.sub!(/\s*#.*$/, "")

if line.start_with?(/\s*include\s+/)
include_path = Pathname(line.sub(/^\s*include\s+/, "")).expand_path
wildcard = include_path.absolute? ? include_path : directory/include_path

Dir.glob(wildcard.to_s).each do |include_file|
paths += library_paths(include_file)
end
elsif line.empty?
next
else
paths << line
end
end

paths.to_a
end
end
end
end
9 changes: 9 additions & 0 deletions Library/Homebrew/os/linux/ld.rbi
@@ -0,0 +1,9 @@
# typed: strict

module OS
module Linux
module Ld
requires_ancestor { Pathname }
end
end
end
47 changes: 47 additions & 0 deletions Library/Homebrew/test/os/linux/ld_spec.rb
@@ -0,0 +1,47 @@
# frozen_string_literal: true

require "os/linux/ld"
require "tmpdir"

RSpec.describe OS::Linux::Ld do
describe "::library_paths" do
ld_etc = Pathname("")
before do
ld_etc = Pathname(Dir.mktmpdir("homebrew-tests-ld-etc-", Dir.tmpdir))
FileUtils.mkdir [ld_etc/"subdir1", ld_etc/"subdir2"]
(ld_etc/"ld.so.conf").write <<~EOS
# This line is a comment
include #{ld_etc}/subdir1/*.conf # This is an end-of-line comment, should be ignored
# subdir2 is an empty directory
include #{ld_etc}/subdir2/*.conf
/a/b/c
/d/e/f # Indentation on this line should be ignored
/a/b/c # Duplicate entry should be ignored
EOS

(ld_etc/"subdir1/1-1.conf").write <<~EOS
/foo/bar
/baz/qux
EOS

(ld_etc/"subdir1/1-2.conf").write <<~EOS
/g/h/i
EOS

# Empty files (or files containing only whitespace) should be ignored
(ld_etc/"subdir1/1-3.conf").write "\n\t\n\t\n"
(ld_etc/"subdir1/1-4.conf").write ""
end

after do
FileUtils.rm_rf ld_etc
end

it "parses library paths successfully" do
expect(described_class.library_paths(ld_etc/"ld.so.conf")).to eq(%w[/foo/bar /baz/qux /g/h/i /a/b/c /d/e/f])
end
end
end

0 comments on commit 8b31fcc

Please sign in to comment.