authorgravatar for bratishkaerik@getgoogleoff.meEric Joldasov <bratishkaerik@getgoogleoff.me> 2022-08-12 02:34:53+06:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-08-18 19:57:50+03:00
logb97ae88898b181ccc99188544411ff06e88e47ec
tree93669a28e157b1c944450ecb8d6b372e74b8b5d4
parent4055e6055b5c0727f5e85a30760c9bccf525f4de

std.zig.system.NativeTargetInfo: look for a shebang line in /usr/bin/env, if any


1 files changed, 72 insertions(+), 29 deletions(-)

lib/std/zig/system/NativeTargetInfo.zig+72-29
...@@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ...@@ -237,7 +237,7 @@ pub fn detect(allocator: Allocator, cross_target: CrossTarget) DetectError!Nativ
237237
238/// First we attempt to use the executable's own binary. If it is dynamically238/// First we attempt to use the executable's own binary. If it is dynamically
239/// linked, then it should answer both the C ABI question and the dynamic linker question.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, then240/// 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/// we fall back to the defaults.241/// we fall back to the defaults.
242/// TODO Remove the Allocator requirement from this function.242/// TODO Remove the Allocator requirement from this function.
243fn detectAbiAndDynamicLinker(243fn detectAbiAndDynamicLinker(
...@@ -355,37 +355,77 @@ fn detectAbiAndDynamicLinker(...@@ -355,37 +355,77 @@ fn detectAbiAndDynamicLinker(
355 return result;355 return result;
356 }356 }
357357
358 const env_file = std.fs.openFileAbsoluteZ("/usr/bin/env", .{}) catch |err| switch (err) {358 const elf_file = blk: {
359 error.NoSpaceLeft => unreachable,359 // This block looks for a shebang line in /usr/bin/env,
360 error.NameTooLong => unreachable,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 error.PathAlreadyExists => unreachable,361 // doing the same logic recursively in case it finds another shebang line.
362 error.SharingViolation => unreachable,362
363 error.InvalidUtf8 => unreachable,363 // Since /usr/bin/env is hard-coded into the shebang line of many portable scripts, it's a
364 error.BadPathName => unreachable,364 // reasonably reliable path to start with.
365 error.PipeBusy => unreachable,365 var file_name: []const u8 = "/usr/bin/env";
366 error.FileLocksNotSupported => unreachable,366 // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1)
367 error.WouldBlock => unreachable,367 var buffer: [258]u8 = undefined;
368 error.FileBusy => unreachable, // opened without write permissions368 while (true) {
369369 const file = std.fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) {
370 error.IsDir,370 error.NoSpaceLeft => unreachable,
371 error.NotDir,371 error.NameTooLong => unreachable,
372 error.InvalidHandle,372 error.PathAlreadyExists => unreachable,
373 error.AccessDenied,373 error.SharingViolation => unreachable,
374 error.NoDevice,374 error.InvalidUtf8 => unreachable,
375 error.FileNotFound,375 error.BadPathName => unreachable,
376 error.FileTooBig,376 error.PipeBusy => unreachable,
377 error.Unexpected,377 error.FileLocksNotSupported => unreachable,
378 => return defaultAbiAndDynamicLinker(cpu, os, cross_target),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 },
379393
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();
383425
384 // If Zig is statically linked, such as via distributed binary static builds, the above426 // 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.427 // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file.
386 // Since that path is hard-coded into the shebang line of many portable scripts, it's a428 return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
387 // reasonably reliable path to check for.
388 return abiAndDynamicLinkerFromFile(env_file, cpu, os, ld_info_list, cross_target) catch |err| switch (err) {
389 error.FileSystem,429 error.FileSystem,
390 error.SystemResources,430 error.SystemResources,
391 error.SymLinkLoop,431 error.SymLinkLoop,
...@@ -403,7 +443,10 @@ fn detectAbiAndDynamicLinker(...@@ -403,7 +443,10 @@ fn detectAbiAndDynamicLinker(
403 error.UnexpectedEndOfFile,443 error.UnexpectedEndOfFile,
404 error.NameTooLong,444 error.NameTooLong,
405 // Finally, we fall back on the standard path.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}
409452