exec.cpp revision 13ec1cf3da6f92defec62492a4a94ada4ee35aaf
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#include <sys/types.h> 31#include <sys/uio.h> 32 33#include <errno.h> 34#include <limits.h> 35#include <paths.h> 36#include <stdarg.h> 37#include <stdio.h> 38#include <stdlib.h> 39#include <string.h> 40#include <unistd.h> 41 42extern "C" char** environ; 43 44enum ExecVariant { kIsExecL, kIsExecLE, kIsExecLP }; 45 46static int __execl(const char* name, const char* argv0, ExecVariant variant, va_list ap) { 47 // Count the arguments. 48 va_list count_ap; 49 va_copy(count_ap, ap); 50 size_t n = 1; 51 while (va_arg(count_ap, char*) != nullptr) { 52 ++n; 53 } 54 va_end(count_ap); 55 56 // Construct the new argv. 57 char* argv[n + 1]; 58 argv[0] = const_cast<char*>(argv0); 59 n = 1; 60 while ((argv[n] = va_arg(ap, char*)) != nullptr) { 61 ++n; 62 } 63 64 // Collect the argp too. 65 char** argp = (variant == kIsExecLE) ? va_arg(ap, char**) : environ; 66 67 va_end(ap); 68 69 return (variant == kIsExecLP) ? execvp(name, argv) : execve(name, argv, argp); 70} 71 72int execl(const char* name, const char* arg, ...) { 73 va_list ap; 74 va_start(ap, arg); 75 int result = __execl(name, arg, kIsExecL, ap); 76 va_end(ap); 77 return result; 78} 79 80int execle(const char* name, const char* arg, ...) { 81 va_list ap; 82 va_start(ap, arg); 83 int result = __execl(name, arg, kIsExecLE, ap); 84 va_end(ap); 85 return result; 86} 87 88int execlp(const char* name, const char* arg, ...) { 89 va_list ap; 90 va_start(ap, arg); 91 int result = __execl(name, arg, kIsExecLP, ap); 92 va_end(ap); 93 return result; 94} 95 96int execv(const char* name, char* const* argv) { 97 return execve(name, argv, environ); 98} 99 100int execvp(const char* name, char* const* argv) { 101 return execvpe(name, argv, environ); 102} 103 104static int __exec_as_script(const char* buf, char* const* argv, char* const* envp) { 105 size_t arg_count = 1; 106 while (argv[arg_count] != nullptr) ++arg_count; 107 108 const char* script_argv[arg_count + 2]; 109 script_argv[0] = "sh"; 110 script_argv[1] = buf; 111 memcpy(script_argv + 2, argv + 1, arg_count * sizeof(char*)); 112 return execve(_PATH_BSHELL, const_cast<char**>(script_argv), envp); 113} 114 115int execvpe(const char* name, char* const* argv, char* const* envp) { 116 // Do not allow null name. 117 if (name == nullptr || *name == '\0') { 118 errno = ENOENT; 119 return -1; 120 } 121 122 // If it's an absolute or relative path name, it's easy. 123 if (strchr(name, '/') && execve(name, argv, envp) == -1) { 124 if (errno == ENOEXEC) return __exec_as_script(name, argv, envp); 125 return -1; 126 } 127 128 // Get the path we're searching. 129 const char* path = getenv("PATH"); 130 if (path == nullptr) path = _PATH_DEFPATH; 131 132 // Make a writable copy. 133 size_t len = strlen(path) + 1; 134 char writable_path[len]; 135 memcpy(writable_path, path, len); 136 137 bool saw_EACCES = false; 138 139 // Try each element of $PATH in turn... 140 char* strsep_buf = writable_path; 141 const char* dir; 142 while ((dir = strsep(&strsep_buf, ":"))) { 143 // It's a shell path: double, leading and trailing colons 144 // mean the current directory. 145 if (*dir == '\0') dir = const_cast<char*>("."); 146 147 size_t dir_len = strlen(dir); 148 size_t name_len = strlen(name); 149 150 char buf[dir_len + 1 + name_len + 1]; 151 mempcpy(mempcpy(mempcpy(buf, dir, dir_len), "/", 1), name, name_len + 1); 152 153 execve(buf, argv, envp); 154 switch (errno) { 155 case EISDIR: 156 case ELOOP: 157 case ENAMETOOLONG: 158 case ENOENT: 159 case ENOTDIR: 160 break; 161 case ENOEXEC: 162 return __exec_as_script(buf, argv, envp); 163 case EACCES: 164 saw_EACCES = true; 165 break; 166 default: 167 return -1; 168 } 169 } 170 if (saw_EACCES) errno = EACCES; 171 return -1; 172} 173