diff options
| author | Eric Joldasov <bratishkaerik@getgoogleoff.me> | 2022-08-12 02:34:53 +0600 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2022-08-18 19:57:50 +0300 |
| commit | b97ae88898b181ccc99188544411ff06e88e47ec (patch) | |
| tree | 93669a28e157b1c944450ecb8d6b372e74b8b5d4 /lib/std | |
| parent | 4055e6055b5c0727f5e85a30760c9bccf525f4de (diff) | |
| download | zig-b97ae88898b181ccc99188544411ff06e88e47ec.tar.gz zig-b97ae88898b181ccc99188544411ff06e88e47ec.zip | |
std.zig.system.NativeTargetInfo: look for a shebang line in /usr/bin/env, if any
Diffstat (limited to 'lib/std')
| -rw-r--r-- | lib/std/zig/system/NativeTargetInfo.zig | 101 |
1 files changed, 72 insertions, 29 deletions
diff --git a/lib/std/zig/system/NativeTargetInfo.zig b/lib/std/zig/system/NativeTargetInfo.zig index 002ad49d64..6dcedd93b8 100644 --- a/lib/std/zig/system/NativeTargetInfo.zig +++ b/lib/std/zig/system/NativeTargetInfo.zig @@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ /// First we attempt to use the executable's own binary. If it is dynamically /// linked, then it should answer both the C ABI question and the dynamic linker question. -/// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then +/// If it is statically linked, then we try /usr/bin/env (or the file it references in shebang). If that does not provide the answer, then /// we fall back to the defaults. /// TODO Remove the Allocator requirement from this function. fn detectAbiAndDynamicLinker( @@ -355,37 +355,77 @@ fn detectAbiAndDynamicLinker( return result; } - const env_file = std.fs.openFileAbsoluteZ("/usr/bin/env", .{}) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, - error.NameTooLong => unreachable, - error.PathAlreadyExists => unreachable, - error.SharingViolation => unreachable, - error.InvalidUtf8 => unreachable, - error.BadPathName => unreachable, - error.PipeBusy => unreachable, - error.FileLocksNotSupported => unreachable, - error.WouldBlock => unreachable, - error.FileBusy => unreachable, // opened without write permissions - - error.IsDir, - error.NotDir, - error.InvalidHandle, - error.AccessDenied, - error.NoDevice, - error.FileNotFound, - error.FileTooBig, - error.Unexpected, - => return defaultAbiAndDynamicLinker(cpu, os, cross_target), + const elf_file = blk: { + // This block looks for a shebang line in /usr/bin/env, + // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead, + // doing the same logic recursively in case it finds another shebang line. + + // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a + // reasonably reliable path to start with. + var file_name: []const u8 = "/usr/bin/env"; + // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1) + var buffer: [258]u8 = undefined; + while (true) { + const file = std.fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { + error.NoSpaceLeft => unreachable, + error.NameTooLong => unreachable, + error.PathAlreadyExists => unreachable, + error.SharingViolation => unreachable, + error.InvalidUtf8 => unreachable, + error.BadPathName => unreachable, + error.PipeBusy => unreachable, + error.FileLocksNotSupported => unreachable, + error.WouldBlock => unreachable, + error.FileBusy => unreachable, // opened without write permissions + + error.IsDir, + error.NotDir, + error.InvalidHandle, + error.AccessDenied, + error.NoDevice, + error.FileNotFound, + error.FileTooBig, + error.Unexpected, + => |e| { + std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)}); + return defaultAbiAndDynamicLinker(cpu, os, cross_target); + }, - else => |e| return e, + else => |e| return e, + }; + + 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, + => break :blk file, + + else => |e| { + file.close(); + return e; + }, + }; + if (!mem.startsWith(u8, line, "#!")) break :blk file; + var it = std.mem.tokenize(u8, line[2..], " "); + file.close(); + file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); + } }; - defer env_file.close(); + defer elf_file.close(); // If Zig is statically linked, such as via distributed binary static builds, the above - // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. - // Since that path is hard-coded into the shebang line of many portable scripts, it's a - // reasonably reliable path to check for. - return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { + // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. + return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { error.FileSystem, error.SystemResources, error.SymLinkLoop, @@ -403,7 +443,10 @@ fn detectAbiAndDynamicLinker( error.UnexpectedEndOfFile, error.NameTooLong, // Finally, we fall back on the standard path. - => defaultAbiAndDynamicLinker(cpu, os, cross_target), + => |e| { + std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)}); + return defaultAbiAndDynamicLinker(cpu, os, cross_target); + }, }; } |
