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'. */ 39int 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 case ENOENT: 97 case ESTALE: 98 case ENOTDIR: 99 /* Those errors indicate the file is missing or not executable 100 by us, in which case we want to just try the next path 101 directory. */ 102 case ENODEV: 103 case ETIMEDOUT: 104 /* Some strange filesystems like AFS return even 105 stranger error numbers. They cannot reasonably mean 106 anything else so ignore those, too. */ 107 case ENOEXEC: 108 /* We won't go searching for the shell 109 * if it is not executable - the Linux 110 * kernel already handles this enough, 111 * for us. */ 112 break; 113 114 default: 115 /* Some other error means we found an executable file, but 116 something went wrong executing it; return the error to our 117 caller. */ 118 return -errno; 119 } 120 } while (*p++ != '\0'); 121 122 /* We tried every element and none of them worked. */ 123 if (got_eacces) 124 /* At least one failure was due to permissions, so report that 125 error. */ 126 return -EACCES; 127 } 128 129 /* Return the error from the last attempt (probably ENOENT). */ 130 return -errno; 131} 132#ifdef TEST 133int main(int argc, char**argv) 134{ 135 char buf[PATH_MAX]; 136 int ret; 137 argc--; 138 if (!argc) { 139 fprintf(stderr, "Not enough arguments\n"); 140 return 1; 141 } 142 argv++; 143 if (ret = execvp_noalloc(buf, argv[0], argv)) { 144 errno = -ret; 145 perror("execvp_noalloc"); 146 } 147 return 0; 148} 149#endif 150