1 /* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c. 2 Original copyright notice follows: 3 4 Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc. 5 This file is part of the GNU C Library. 6 7 The GNU C Library is free software; you can redistribute it and/or 8 modify it under the terms of the GNU Lesser General Public 9 License as published by the Free Software Foundation; either 10 version 2.1 of the License, or (at your option) any later version. 11 12 The GNU C Library is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 Lesser General Public License for more details. 16 17 You should have received a copy of the GNU Lesser General Public 18 License along with the GNU C Library; if not, write to the Free 19 Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 20 02111-1307 USA. */ 21 #include <unistd.h> 22 23 #include <stdbool.h> 24 #include <stdlib.h> 25 #include <string.h> 26 #include <errno.h> 27 #include <limits.h> 28 29 #ifndef TEST 30 #include <um_malloc.h> 31 #else 32 #include <stdio.h> 33 #define um_kmalloc malloc 34 #endif 35 #include <os.h> 36 37 /* Execute FILE, searching in the `PATH' environment variable if it contains 38 no slashes, with arguments ARGV and environment from `environ'. */ 39 int execvp_noalloc(char *buf, const char *file, char *const argv[]) 40 { 41 if (*file == '\0') { 42 return -ENOENT; 43 } 44 45 if (strchr (file, '/') != NULL) { 46 /* Don't search when it contains a slash. */ 47 execv(file, argv); 48 } else { 49 int got_eacces; 50 size_t len, pathlen; 51 char *name, *p; 52 char *path = getenv("PATH"); 53 if (path == NULL) 54 path = ":/bin:/usr/bin"; 55 56 len = strlen(file) + 1; 57 pathlen = strlen(path); 58 /* Copy the file name at the top. */ 59 name = memcpy(buf + pathlen + 1, file, len); 60 /* And add the slash. */ 61 *--name = '/'; 62 63 got_eacces = 0; 64 p = path; 65 do { 66 char *startp; 67 68 path = p; 69 //Let's avoid this GNU extension. 70 //p = strchrnul (path, ':'); 71 p = strchr(path, ':'); 72 if (!p) 73 p = strchr(path, '\0'); 74 75 if (p == path) 76 /* Two adjacent colons, or a colon at the beginning or the end 77 of `PATH' means to search the current directory. */ 78 startp = name + 1; 79 else 80 startp = memcpy(name - (p - path), path, p - path); 81 82 /* Try to execute this name. If it works, execv will not return. */ 83 execv(startp, argv); 84 85 /* 86 if (errno == ENOEXEC) { 87 } 88 */ 89 90 switch (errno) { 91 case EACCES: 92 /* Record the we got a `Permission denied' error. If we end 93 up finding no executable we can use, we want to diagnose 94 that we did find one but were denied access. */ 95 got_eacces = 1; 96 break; 97 case ENOENT: 98 case ESTALE: 99 case ENOTDIR: 100 /* Those errors indicate the file is missing or not executable 101 by us, in which case we want to just try the next path 102 directory. */ 103 case ENODEV: 104 case ETIMEDOUT: 105 /* Some strange filesystems like AFS return even 106 stranger error numbers. They cannot reasonably mean 107 anything else so ignore those, too. */ 108 case ENOEXEC: 109 /* We won't go searching for the shell 110 * if it is not executable - the Linux 111 * kernel already handles this enough, 112 * for us. */ 113 break; 114 115 default: 116 /* Some other error means we found an executable file, but 117 something went wrong executing it; return the error to our 118 caller. */ 119 return -errno; 120 } 121 } while (*p++ != '\0'); 122 123 /* We tried every element and none of them worked. */ 124 if (got_eacces) 125 /* At least one failure was due to permissions, so report that 126 error. */ 127 return -EACCES; 128 } 129 130 /* Return the error from the last attempt (probably ENOENT). */ 131 return -errno; 132 } 133 #ifdef TEST 134 int main(int argc, char**argv) 135 { 136 char buf[PATH_MAX]; 137 int ret; 138 argc--; 139 if (!argc) { 140 os_warn("Not enough arguments\n"); 141 return 1; 142 } 143 argv++; 144 if (ret = execvp_noalloc(buf, argv[0], argv)) { 145 errno = -ret; 146 perror("execvp_noalloc"); 147 } 148 return 0; 149 } 150 #endif 151