| ... | @@ -7191,25 +7191,35 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex | ... | @@ -7191,25 +7191,35 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex |
| 7191 | return error.FileNotFound; | 7191 | return error.FileNotFound; |
| 7192 | | 7192 | |
| 7193 | const argv0 = std.mem.span(std.os.argv[0]); | 7193 | 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) { |
| 7195 | // argv[0] is a path (relative or absolute): use realpath(3) directly | 7195 | // argv[0] is a path (relative or absolute): use realpath(3) directly |
| 7196 | const current_thread = Thread.getCurrent(t); | 7196 | const current_thread = Thread.getCurrent(t); |
| 7197 | var resolved_buf: [std.c.PATH_MAX]u8 = undefined; | 7197 | var resolved_buf: [std.c.PATH_MAX]u8 = undefined; |
| 7198 | { | 7198 | try current_thread.beginSyscall(); |
| 7199 | try current_thread.beginSyscall(); | 7199 | while (true) { |
| 7200 | defer current_thread.endSyscall(); | 7200 | if (std.c.realpath(std.os.argv[0], &resolved_buf)) |p| { |
| 7201 | _ = std.c.realpath(std.os.argv[0], &resolved_buf) orelse switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) { | 7201 | assert(p == &resolved_buf); |
| 7202 | .SUCCESS => unreachable, | 7202 | break current_thread.endSyscall(); |
| 7203 | .ACCES => return error.AccessDenied, | 7203 | } else switch (@as(std.c.E, @enumFromInt(std.c._errno().*))) { |
| 7204 | .INVAL => unreachable, // the pathname argument is a null pointer | 7204 | .INTR => { |
| 7205 | .IO => return error.InputOutput, | 7205 | try current_thread.checkCancel(); |
| 7206 | .LOOP => return error.SymLinkLoop, | 7206 | continue; |
| 7207 | .NAMETOOLONG => return error.NameTooLong, | 7207 | }, |
| 7208 | .NOENT => return error.FileNotFound, | 7208 | else => |e| { |
| 7209 | .NOTDIR => return error.NotDir, | 7209 | current_thread.endSyscall(); |
| 7210 | .NOMEM => unreachable, // sufficient storage space is unavailable for allocation | 7210 | switch (e) { |
| 7211 | else => |err| return posix.unexpectedErrno(err), | 7211 | .ACCES => return error.AccessDenied, |
| 7212 | }; | 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 | } |
| 7213 | } | 7223 | } |
| 7214 | const resolved = std.mem.sliceTo(&resolved_buf, 0); | 7224 | const resolved = std.mem.sliceTo(&resolved_buf, 0); |
| 7215 | if (resolved.len > out_buffer.len) | 7225 | if (resolved.len > out_buffer.len) |
| ... | @@ -7220,23 +7230,46 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex | ... | @@ -7220,23 +7230,46 @@ fn processExecutablePath(userdata: ?*anyopaque, out_buffer: []u8) std.process.Ex |
| 7220 | // argv[0] is not empty (and not a path): search PATH | 7230 | // argv[0] is not empty (and not a path): search PATH |
| 7221 | const current_thread = Thread.getCurrent(t); | 7231 | const current_thread = Thread.getCurrent(t); |
| 7222 | const PATH = posix.getenvZ("PATH") orelse return error.FileNotFound; | 7232 | const PATH = posix.getenvZ("PATH") orelse return error.FileNotFound; |
| 7223 | var it = std.mem.tokenizeScalar(u8, PATH, std.fs.path.delimiter); | 7233 | var it = std.mem.tokenizeScalar(u8, PATH, ':'); |
| 7224 | while (it.next()) |dir| { | 7234 | it: while (it.next()) |dir| { |
| 7225 | var prospect_buf: [std.c.PATH_MAX]u8 = undefined; | 7235 | var resolved_path_buf: [std.c.PATH_MAX]u8 = undefined; |
| 7226 | _ = std.fmt.bufPrintSentinel( | 7236 | const resolved_path = std.fmt.bufPrintSentinel(&resolved_path_buf, "{s}/{s}", .{ |
| 7227 | &prospect_buf, | 7237 | dir, std.os.argv[0], |
| 7228 | "{s}" ++ std.fs.path.sep_str_posix ++ "{s}", | 7238 | }, 0) catch continue; |
| 7229 | .{ dir, std.os.argv[0] }, | | |
| 7230 | 0, | | |
| 7231 | ) catch continue; | | |
| 7232 | | 7239 | |
| 7233 | var resolved_buf: [std.c.PATH_MAX]u8 = undefined; | 7240 | var resolved_buf: [std.c.PATH_MAX]u8 = undefined; |
| 7234 | try current_thread.beginSyscall(); | 7241 | try current_thread.beginSyscall(); |
| 7235 | _ = std.c.realpath(@ptrCast(&prospect_buf), &resolved_buf) orelse { | 7242 | while (true) { |
| 7236 | current_thread.endSyscall(); | 7243 | if (std.c.realpath(resolved_path, &resolved_buf)) |p| { |
| 7237 | continue; | 7244 | assert(p == &resolved_buf); |
| 7238 | }; | 7245 | break current_thread.endSyscall(); |
| 7239 | 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 | } |
| 7240 | const resolved = std.mem.sliceTo(&resolved_buf, 0); | 7273 | const resolved = std.mem.sliceTo(&resolved_buf, 0); |
| 7241 | if (resolved.len > out_buffer.len) | 7274 | if (resolved.len > out_buffer.len) |
| 7242 | return error.NameTooLong; | 7275 | return error.NameTooLong; |