execvp.c (1798B)
1 /* 2 * execvp.c - execute a file, searching PATH 3 * Copyright (C) 2026. All rights reserved. 4 */ 5 6 #include "libc.h" 7 8 char **environ; 9 10 int execvp(const char *file, char *const argv[]) { 11 static char *empty_env[] = { NULL }; 12 char **env = (environ != NULL) ? environ : empty_env; 13 14 if (file == NULL || *file == '\0') { 15 errno = ENOENT; 16 return -1; 17 } 18 19 if (strchr(file, '/') != NULL) { 20 return execve(file, argv, env); 21 } 22 23 const char *path_env = NULL; 24 for (char **ep = env; *ep != NULL; ++ep) { 25 if (ep[0][0] == 'P' && ep[0][1] == 'A' && 26 ep[0][2] == 'T' && ep[0][3] == 'H' && ep[0][4] == '=') { 27 path_env = *ep + 5; 28 break; 29 } 30 } 31 32 if (path_env == NULL) { 33 path_env = "/bin:/usr/bin"; 34 } 35 36 char path_buf[1024]; 37 size_t file_len = strlen(file); 38 int saved_errno = ENOENT; 39 40 if (file_len >= sizeof(path_buf)) { 41 errno = ENAMETOOLONG; 42 return -1; 43 } 44 45 const char *p = path_env; 46 for (;;) { 47 const char *start = p; 48 while (*p != '\0' && *p != ':') { 49 p++; 50 } 51 52 size_t dir_len = (size_t)(p - start); 53 size_t needed = file_len + 1; 54 55 if (dir_len != 0) { 56 if (dir_len > sizeof(path_buf) - needed - 1) { 57 saved_errno = ENAMETOOLONG; 58 goto next_path; 59 } 60 needed += dir_len + 1; 61 } 62 63 if (needed <= sizeof(path_buf)) { 64 if (dir_len == 0) { 65 memcpy(path_buf, file, file_len + 1); 66 } else { 67 memcpy(path_buf, start, dir_len); 68 path_buf[dir_len] = '/'; 69 memcpy(path_buf + dir_len + 1, file, file_len + 1); 70 } 71 72 if (execve(path_buf, argv, env) == -1) { 73 saved_errno = errno; 74 } 75 } else { 76 saved_errno = ENAMETOOLONG; 77 } 78 79 next_path: 80 if (*p == '\0') { 81 break; 82 } 83 p++; 84 } 85 86 errno = saved_errno; 87 return -1; 88 }