@@ -203,15 +203,11 @@ pub fn posixDup2(old_fd: i32, new_fd: i32) -> %void {
203
203
/// This function must allocate memory to add a null terminating bytes on path and each arg.
204
204
/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
205
205
/// pointers after the args and after the environment variables.
206
- /// Also make the first arg equal to path.
207
- pub fn posixExecve (path : []const u8 , argv : []const []const u8 , env_map : & const BufMap ,
208
- allocator : & Allocator ) - > % usize
206
+ /// Also make the first arg equal to exe_path.
207
+ /// This function also uses the PATH environment variable to get the full path to the executable.
208
+ pub fn posixExecve (exe_path : []const u8 , argv : []const []const u8 , env_map : & const BufMap ,
209
+ allocator : & Allocator ) - > % void
209
210
{
210
- const path_buf = % return allocator .alloc (u8 , path .len + 1 );
211
- defer allocator .free (path_buf );
212
- @memcpy (& path_buf [0 ], & path [0 ], path .len );
213
- path_buf [path .len ] = 0 ;
214
-
215
211
const argv_buf = % return allocator .alloc (? & const u8 , argv .len + 2 );
216
212
mem .set (? & const u8 , argv_buf , null );
217
213
defer {
@@ -222,10 +218,10 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B
222
218
allocator .free (argv_buf );
223
219
}
224
220
{
225
- // Add path to the first argument.
226
- const arg_buf = % return allocator .alloc (u8 , path .len + 1 );
227
- @memcpy (& arg_buf [0 ], path .ptr , path .len );
228
- arg_buf [path .len ] = 0 ;
221
+ // Add exe_path to the first argument.
222
+ const arg_buf = % return allocator .alloc (u8 , exe_path .len + 1 );
223
+ @memcpy (& arg_buf [0 ], exe_path .ptr , exe_path .len );
224
+ arg_buf [exe_path .len ] = 0 ;
229
225
230
226
argv_buf [0 ] = arg_buf .ptr ;
231
227
}
@@ -266,7 +262,58 @@ pub fn posixExecve(path: []const u8, argv: []const []const u8, env_map: &const B
266
262
}
267
263
envp_buf [envp_count ] = null ;
268
264
269
- return posix .execve (path_buf .ptr , argv_buf .ptr , envp_buf .ptr );
265
+
266
+ if (mem .indexOfScalar (u8 , exe_path , '/' ) != null ) {
267
+ // +1 for the null terminating byte
268
+ const path_buf = % return allocator .alloc (u8 , exe_path .len + 1 );
269
+ defer allocator .free (path_buf );
270
+ @memcpy (& path_buf [0 ], & exe_path [0 ], exe_path .len );
271
+ path_buf [exe_path .len ] = 0 ;
272
+ return posixExecveErrnoToErr (posix .getErrno (posix .execve (path_buf .ptr , argv_buf .ptr , envp_buf .ptr )));
273
+ }
274
+
275
+ const PATH = getEnv ("PATH" ) ?? ([]const u8 )("/usr/local/bin:/bin/:/usr/bin" ); // TODO issue #299
276
+ // PATH.len because it is >= the largest search_path
277
+ // +1 for the / to join the search path and exe_path
278
+ // +1 for the null terminating byte
279
+ const path_buf = % return allocator .alloc (u8 , PATH .len + exe_path .len + 2 );
280
+ defer allocator .free (path_buf );
281
+ var it = mem .split (PATH , ':' );
282
+ var seen_eacces = false ;
283
+ var err : usize = undefined ;
284
+ while (true ) {
285
+ const search_path = it .next () ?? break ;
286
+ mem .copy (u8 , path_buf , search_path );
287
+ path_buf [search_path .len ] = '/' ;
288
+ mem .copy (u8 , path_buf [search_path .len + 1 ... ], exe_path );
289
+ path_buf [search_path .len + exe_path .len + 2 ] = 0 ;
290
+ err = posix .getErrno (posix .execve (path_buf .ptr , argv_buf .ptr , envp_buf .ptr ));
291
+ assert (err > 0 );
292
+ if (err == errno .EACCES ) {
293
+ seen_eacces = true ;
294
+ } else if (err != errno .ENOENT ) {
295
+ return posixExecveErrnoToErr (err );
296
+ }
297
+ }
298
+ if (seen_eacces ) {
299
+ err = errno .EACCES ;
300
+ }
301
+ return posixExecveErrnoToErr (err );
302
+ }
303
+
304
+ fn posixExecveErrnoToErr (err : usize ) - > error {
305
+ assert (err > 0 );
306
+ return switch (err ) {
307
+ errno .EFAULT = > unreachable ,
308
+ errno .E2BIG , errno .EMFILE , errno .ENAMETOOLONG , errno .ENFILE , errno .ENOMEM = > error .SysResources ,
309
+ errno .EACCES , errno .EPERM = > error .AccessDenied ,
310
+ errno .EINVAL , errno .ENOEXEC = > error .InvalidExe ,
311
+ errno .EIO , errno .ELOOP = > error .FileSystem ,
312
+ errno .EISDIR = > error .IsDir ,
313
+ errno .ENOENT , errno .ENOTDIR = > error .FileNotFound ,
314
+ errno .ETXTBSY = > error .FileBusy ,
315
+ else = > error .Unexpected ,
316
+ };
270
317
}
271
318
272
319
pub var environ_raw : []& u8 = undefined ;
0 commit comments