diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2022-09-08 20:49:16 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2022-09-08 20:52:49 -0700 |
| commit | 9f40f34501ef086d18e4570416c078a7ad508628 (patch) | |
| tree | d4c24be3d5c7fa50f96fc54e7880f0c37bba422f /lib/std | |
| parent | c668396941f19a5c015014822d980bbe9f2bc585 (diff) | |
| download | zig-9f40f34501ef086d18e4570416c078a7ad508628.tar.gz zig-9f40f34501ef086d18e4570416c078a7ad508628.zip | |
std.zig.system.NativeTargetInfo: restore symlink logic
This is a partial revert of the previous commit, fixing a regression on
Debian. However, the commit additionally improves the
detectAbiAndDynamicLinker function to read more than 1 byte at a time
when detecting a shebang line.
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/zig/system/NativeTargetInfo.zig | 73 |
1 files changed, 57 insertions, 16 deletions
diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig index 7d626be994..11b5ec4191 100644 --- a/lib/std/zig/system/NativeTargetInfo.zig +++ b/lib/std/zig/system/NativeTargetInfo.zig @@ -347,26 +347,17 @@ fn detectAbiAndDynamicLinker( }; errdefer file.close(); - const line = file.reader().readUntilDelimiter(&buffer, '\n') catch |err| switch (err) { - error.IsDir => unreachable, // Handled before - error.AccessDenied => unreachable, - error.WouldBlock => unreachable, // Did not request blocking mode - error.OperationAborted => unreachable, // Windows-only - error.BrokenPipe => unreachable, - error.ConnectionResetByPeer => unreachable, - error.ConnectionTimedOut => unreachable, - error.InputOutput => unreachable, - error.Unexpected => unreachable, - - error.StreamTooLong, - error.EndOfStream, - error.NotOpenForReading, + const len = preadMin(file, &buffer, 0, buffer.len) catch |err| switch (err) { + error.UnexpectedEndOfFile, + error.UnableToReadElfFile, => break :blk file, else => |e| return e, }; + const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file; + const line = buffer[0..newline]; if (!mem.startsWith(u8, line, "#!")) break :blk file; - var it = std.mem.tokenize(u8, line[2..], " "); + var it = mem.tokenize(u8, line[2..], " "); file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); file.close(); } @@ -375,6 +366,8 @@ fn detectAbiAndDynamicLinker( // If Zig is statically linked, such as via distributed binary static builds, the above // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. + // TODO: inline this function and combine the buffer we already read above to find + // the possible shebang line with the buffer we use for the ELF header. return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { error.FileSystem, error.SystemResources, @@ -586,6 +579,23 @@ fn glibcVerFromSoFile(file: fs.File) !std.builtin.Version { return max_ver; } +fn glibcVerFromLinkName(link_name: []const u8, prefix: []const u8) !std.builtin.Version { + // example: "libc-2.3.4.so" + // example: "libc-2.27.so" + // example: "ld-2.33.so" + const suffix = ".so"; + if (!mem.startsWith(u8, link_name, prefix) or !mem.endsWith(u8, link_name, suffix)) { + return error.UnrecognizedGnuLibCFileName; + } + // chop off "libc-" and ".so" + const link_name_chopped = link_name[prefix.len .. link_name.len - suffix.len]; + return std.builtin.Version.parse(link_name_chopped) catch |err| switch (err) { + error.Overflow => return error.InvalidGnuLibCVersion, + error.InvalidCharacter => return error.InvalidGnuLibCVersion, + error.InvalidVersion => return error.InvalidGnuLibCVersion, + }; +} + pub const AbiAndDynamicLinkerFromFileError = error{ FileSystem, SystemResources, @@ -816,17 +826,48 @@ pub fn abiAndDynamicLinkerFromFile( else => |e| return e, } } - } else if (result.dynamic_linker.get()) |dl_path| { + } else if (result.dynamic_linker.get()) |dl_path| glibc_ver: { // There is no DT_RUNPATH so we try to find libc.so.6 inside the same // directory as the dynamic linker. if (fs.path.dirname(dl_path)) |rpath| { if (glibcVerFromRPath(rpath)) |ver| { result.target.os.version_range.linux.glibc = ver; + break :glibc_ver; } else |err| switch (err) { error.GLibCNotFound => {}, else => |e| return e, } } + + // So far, no luck. Next we try to see if the information is + // present in the symlink data for the dynamic linker path. + var link_buf: [std.os.PATH_MAX]u8 = undefined; + const link_name = std.os.readlink(dl_path, &link_buf) catch |err| switch (err) { + error.NameTooLong => unreachable, + error.InvalidUtf8 => unreachable, // Windows only + error.BadPathName => unreachable, // Windows only + error.UnsupportedReparsePointType => unreachable, // Windows only + + error.AccessDenied, + error.FileNotFound, + error.NotLink, + error.NotDir, + => break :glibc_ver, + + error.SystemResources, + error.FileSystem, + error.SymLinkLoop, + error.Unexpected, + => |e| return e, + }; + result.target.os.version_range.linux.glibc = glibcVerFromLinkName( + fs.path.basename(link_name), + "ld-", + ) catch |err| switch (err) { + error.UnrecognizedGnuLibCFileName, + error.InvalidGnuLibCVersion, + => break :glibc_ver, + }; } } } |
