| ... | ... | @@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ |
| 237 | 237 | |
| 238 | 238 | /// First we attempt to use the executable's own binary. If it is dynamically |
| 239 | 239 | /// linked, then it should answer both the C ABI question and the dynamic linker question. |
| 240 | | /// If it is statically linked, then we try /usr/bin/env. If that does not provide the answer, then |
| 240 | /// 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 |
| 241 | 241 | /// we fall back to the defaults. |
| 242 | 242 | /// TODO Remove the Allocator requirement from this function. |
| 243 | 243 | fn detectAbiAndDynamicLinker( |
| ... | ... | @@ -355,37 +355,77 @@ fn detectAbiAndDynamicLinker( |
| 355 | 355 | return result; |
| 356 | 356 | } |
| 357 | 357 | |
| 358 | | const env_file = std.fs.openFileAbsoluteZ("/usr/bin/env", .{}) catch |err| switch (err) { |
| 359 | | error.NoSpaceLeft => unreachable, |
| 360 | | error.NameTooLong => unreachable, |
| 361 | | error.PathAlreadyExists => unreachable, |
| 362 | | error.SharingViolation => unreachable, |
| 363 | | error.InvalidUtf8 => unreachable, |
| 364 | | error.BadPathName => unreachable, |
| 365 | | error.PipeBusy => unreachable, |
| 366 | | error.FileLocksNotSupported => unreachable, |
| 367 | | error.WouldBlock => unreachable, |
| 368 | | error.FileBusy => unreachable, // opened without write permissions |
| 369 | | |
| 370 | | error.IsDir, |
| 371 | | error.NotDir, |
| 372 | | error.InvalidHandle, |
| 373 | | error.AccessDenied, |
| 374 | | error.NoDevice, |
| 375 | | error.FileNotFound, |
| 376 | | error.FileTooBig, |
| 377 | | error.Unexpected, |
| 378 | | => return defaultAbiAndDynamicLinker(cpu, os, cross_target), |
| 358 | const elf_file = blk: { |
| 359 | // This block looks for a shebang line in /usr/bin/env, |
| 360 | // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead, |
| 361 | // doing the same logic recursively in case it finds another shebang line. |
| 362 | |
| 363 | // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a |
| 364 | // reasonably reliable path to start with. |
| 365 | var file_name: []const u8 = "/usr/bin/env"; |
| 366 | // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1) |
| 367 | var buffer: [258]u8 = undefined; |
| 368 | while (true) { |
| 369 | const file = std.fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) { |
| 370 | error.NoSpaceLeft => unreachable, |
| 371 | error.NameTooLong => unreachable, |
| 372 | error.PathAlreadyExists => unreachable, |
| 373 | error.SharingViolation => unreachable, |
| 374 | error.InvalidUtf8 => unreachable, |
| 375 | error.BadPathName => unreachable, |
| 376 | error.PipeBusy => unreachable, |
| 377 | error.FileLocksNotSupported => unreachable, |
| 378 | error.WouldBlock => unreachable, |
| 379 | error.FileBusy => unreachable, // opened without write permissions |
| 380 | |
| 381 | error.IsDir, |
| 382 | error.NotDir, |
| 383 | error.InvalidHandle, |
| 384 | error.AccessDenied, |
| 385 | error.NoDevice, |
| 386 | error.FileNotFound, |
| 387 | error.FileTooBig, |
| 388 | error.Unexpected, |
| 389 | => |e| { |
| 390 | std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)}); |
| 391 | return defaultAbiAndDynamicLinker(cpu, os, cross_target); |
| 392 | }, |
| 379 | 393 | |
| 380 | | else => |e| return e, |
| 394 | else => |e| return e, |
| 395 | }; |
| 396 | |
| 397 | const line = file.reader().readUntilDelimiter(&buffer, '\n') catch |err| switch (err) { |
| 398 | error.IsDir => unreachable, // Handled before |
| 399 | error.AccessDenied => unreachable, |
| 400 | error.WouldBlock => unreachable, // Did not request blocking mode |
| 401 | error.OperationAborted => unreachable, // Windows-only |
| 402 | error.BrokenPipe => unreachable, |
| 403 | error.ConnectionResetByPeer => unreachable, |
| 404 | error.ConnectionTimedOut => unreachable, |
| 405 | error.InputOutput => unreachable, |
| 406 | error.Unexpected => unreachable, |
| 407 | |
| 408 | error.StreamTooLong, |
| 409 | error.EndOfStream, |
| 410 | error.NotOpenForReading, |
| 411 | => break :blk file, |
| 412 | |
| 413 | else => |e| { |
| 414 | file.close(); |
| 415 | return e; |
| 416 | }, |
| 417 | }; |
| 418 | if (!mem.startsWith(u8, line, "#!")) break :blk file; |
| 419 | var it = std.mem.tokenize(u8, line[2..], " "); |
| 420 | file.close(); |
| 421 | file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, cross_target); |
| 422 | } |
| 381 | 423 | }; |
| 382 | | defer env_file.close(); |
| 424 | defer elf_file.close(); |
| 383 | 425 | |
| 384 | 426 | // If Zig is statically linked, such as via distributed binary static builds, the above |
| 385 | | // trick won't work. The next thing we fall back to is the same thing, but for /usr/bin/env. |
| 386 | | // Since that path is hard-coded into the shebang line of many portable scripts, it's a |
| 387 | | // reasonably reliable path to check for. |
| 388 | | return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { |
| 427 | // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file. |
| 428 | return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) { |
| 389 | 429 | error.FileSystem, |
| 390 | 430 | error.SystemResources, |
| 391 | 431 | error.SymLinkLoop, |
| ... | ... | @@ -403,7 +443,10 @@ fn detectAbiAndDynamicLinker( |
| 403 | 443 | error.UnexpectedEndOfFile, |
| 404 | 444 | error.NameTooLong, |
| 405 | 445 | // Finally, we fall back on the standard path. |
| 406 | | => defaultAbiAndDynamicLinker(cpu, os, cross_target), |
| 446 | => |e| { |
| 447 | std.log.warn("Encoutered error: {s}, falling back to default ABI and dynamic linker.\n", .{@errorName(e)}); |
| 448 | return defaultAbiAndDynamicLinker(cpu, os, cross_target); |
| 449 | }, |
| 407 | 450 | }; |
| 408 | 451 | } |
| 409 | 452 | |