authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-21 18:31:46-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-12-23 22:15:11-08:00
log1132e329d3bf6cbb1959046c4128175038c4bbed
treeed741d065b35d873ef9eabd3d5ae7f58d41ca8db
parent7014976d3dc38320257871f0e218ded987843bc1

std.Io.Threaded: fix up processExecutablePath OpenBSD

* policy is to always handle EINTR from all syscalls * assert the result of realpath * don't ignore errors from realpath * hard-code path separators for code simplicity

1 files changed, 63 insertions(+), 30 deletions(-)

lib/std/Io/Threaded.zig+63-30
......@@ -7191,25 +7191,35 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex
71917191 return error.FileNotFound;
71927192
71937193 const argv0 = std.mem.span(std.os.argv[0]);
7194 if (std.mem.findScalar(u8, argv0, std.fs.path.sep_posix) != null) {
7194 if (std.mem.findScalar(u8, argv0, '/') != null) {
71957195 // argv[0] is a path (relative or absolute): use realpath(3) directly
71967196 const current_thread = Thread.getCurrent(t);
71977197 var resolved_buf: [std.c.PATH_MAX]u8 = undefined;
7198 {
7199 try current_thread.beginSyscall();
7200 defer current_thread.endSyscall();
7201 _ = std.c.realpath(std.os.argv[0], &resolved_buf) orelse switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) {
7202 .SUCCESS => unreachable,
7203 .ACCES => return error.AccessDenied,
7204 .INVAL => unreachable, // the pathname argument is a null pointer
7205 .IO => return error.InputOutput,
7206 .LOOP => return error.SymLinkLoop,
7207 .NAMETOOLONG => return error.NameTooLong,
7208 .NOENT => return error.FileNotFound,
7209 .NOTDIR => return error.NotDir,
7210 .NOMEM => unreachable, // sufficient storage space is unavailable for allocation
7211 else => |err| return posix.unexpectedErrno(err),
7212 };
7198 try current_thread.beginSyscall();
7199 while (true) {
7200 if (std.c.realpath(std.os.argv[0], &resolved_buf)) |p| {
7201 assert(p == &resolved_buf);
7202 break current_thread.endSyscall();
7203 } else switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) {
7204 .INTR => {
7205 try current_thread.checkCancel();
7206 continue;
7207 },
7208 else => |e| {
7209 current_thread.endSyscall();
7210 switch (e) {
7211 .ACCES => return error.AccessDenied,
7212 .INVAL => |err| return errnoBug(err), // the pathname argument is a null pointer
7213 .IO => return error.InputOutput,
7214 .LOOP => return error.SymLinkLoop,
7215 .NAMETOOLONG => return error.NameTooLong,
7216 .NOENT => return error.FileNotFound,
7217 .NOTDIR => return error.NotDir,
7218 .NOMEM => |err| return errnoBug(err), // sufficient storage space is unavailable for allocation
7219 else => |err| return posix.unexpectedErrno(err),
7220 }
7221 },
7222 }
72137223 }
72147224 const resolved = std.mem.sliceTo(&resolved_buf, 0);
72157225 if (resolved.len > out_buffer.len)
......@@ -7220,23 +7230,46 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex
72207230 // argv[0] is not empty (and not a path): search PATH
72217231 const current_thread = Thread.getCurrent(t);
72227232 const PATH = posix.getenvZ("PATH") orelse return error.FileNotFound;
7223 var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter);
7224 while (it.next()) |dir| {
7225 var prospect_buf: [std.c.PATH_MAX]u8 = undefined;
7226 _ = std.fmt.bufPrintSentinel(
7227 &prospect_buf,
7228 "{s}" ++ std.fs.path.sep_str_posix ++ "{s}",
7229 .{ dir, std.os.argv[0] },
7230 0,
7231 ) catch continue;
7233 var it = std.mem.tokenizeScalar(u8, PATH, ':');
7234 it: while (it.next()) |dir| {
7235 var resolved_path_buf: [std.c.PATH_MAX]u8 = undefined;
7236 const resolved_path = std.fmt.bufPrintSentinel(&resolved_path_buf, "{s}/{s}", .{
7237 dir, std.os.argv[0],
7238 }, 0) catch continue;
72327239
72337240 var resolved_buf: [std.c.PATH_MAX]u8 = undefined;
72347241 try current_thread.beginSyscall();
7235 _ = std.c.realpath(@ptrCast(&prospect_buf), &resolved_buf) orelse {
7236 current_thread.endSyscall();
7237 continue;
7238 };
7239 current_thread.endSyscall();
7242 while (true) {
7243 if (std.c.realpath(resolved_path, &resolved_buf)) |p| {
7244 assert(p == &resolved_buf);
7245 break current_thread.endSyscall();
7246 } else switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) {
7247 .INTR => {
7248 try current_thread.checkCancel();
7249 continue;
7250 },
7251 .NAMETOOLONG => {
7252 current_thread.endSyscall();
7253 return error.NameTooLong;
7254 },
7255 .NOMEM => {
7256 current_thread.endSyscall();
7257 return error.SystemResources;
7258 },
7259 .IO => {
7260 current_thread.endSyscall();
7261 return error.InputOutput;
7262 },
7263 .ACCES, .LOOP, .NOENT, .NOTDIR => {
7264 current_thread.endSyscall();
7265 continue :it;
7266 },
7267 else => |err| {
7268 current_thread.endSyscall();
7269 return posix.unexpectedErrno(err);
7270 },
7271 }
7272 }
72407273 const resolved = std.mem.sliceTo(&resolved_buf, 0);
72417274 if (resolved.len > out_buffer.len)
72427275 return error.NameTooLong;