1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 * Copyright 2024 Oxide Computer Company 26 */ 27 28 /* Copyright (c) 1988 AT&T */ 29 /* All Rights Reserved */ 30 31 /* 32 * execlp(name, arg,...,0) (like execl, but does path search) 33 * execvp(name, argv) (like execv, but does path search) 34 * execvpe(name, argv, envp) (like execve, but does path search) 35 */ 36 37 #pragma weak _execlp = execlp 38 #pragma weak _execvp = execvp 39 40 #include "lint.h" 41 #include <sys/types.h> 42 #include <unistd.h> 43 #include <string.h> 44 #include <alloca.h> 45 #include <errno.h> 46 #include <limits.h> 47 #include <stdarg.h> 48 #include <stdlib.h> 49 #include <paths.h> 50 51 static const char *execat(const char *, const char *, char *); 52 53 extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */ 54 55 /*VARARGS1*/ 56 int 57 execlp(const char *name, const char *arg0, ...) 58 { 59 char **argp; 60 va_list args; 61 char **argvec; 62 int err; 63 int nargs = 0; 64 char *nextarg; 65 66 /* 67 * count the number of arguments in the variable argument list 68 * and allocate an argument vector for them on the stack, 69 * adding space for a terminating null pointer at the end 70 * and one additional space for argv[0] which is no longer 71 * counted by the varargs loop. 72 */ 73 74 va_start(args, arg0); 75 76 while (va_arg(args, char *) != (char *)0) 77 nargs++; 78 79 va_end(args); 80 81 /* 82 * load the arguments in the variable argument list 83 * into the argument vector and add the terminating null pointer 84 */ 85 86 va_start(args, arg0); 87 /* workaround for bugid 1242839 */ 88 argvec = alloca((size_t)((nargs + 2) * sizeof (char *))); 89 nextarg = va_arg(args, char *); 90 argp = argvec; 91 *argp++ = (char *)arg0; 92 while (nargs-- && nextarg != (char *)0) { 93 *argp = nextarg; 94 argp++; 95 nextarg = va_arg(args, char *); 96 } 97 va_end(args); 98 *argp = (char *)0; 99 100 /* 101 * call execvp() 102 */ 103 104 err = execvp(name, argvec); 105 return (err); 106 } 107 108 static int 109 execvpe_int(const char *name, char *const *argv, char *const *envp, 110 boolean_t use_env) 111 { 112 const char *pathstr; 113 char fname[PATH_MAX+2]; 114 char *newargs[256]; 115 int i; 116 const char *cp; 117 unsigned etxtbsy = 1; 118 int eacces = 0; 119 120 if (*name == '\0') { 121 errno = ENOENT; 122 return (-1); 123 } 124 if ((pathstr = getenv("PATH")) == NULL) { 125 /* 126 * XPG4: pathstr is equivalent to CSPATH, except that 127 * :/usr/sbin is appended when root, and pathstr must end 128 * with a colon when not root. Keep these paths in sync 129 * with CSPATH in confstr.c. Note that pathstr must end 130 * with a colon when not root so that when name doesn't 131 * contain '/', the last call to execat() will result in an 132 * attempt to execv name from the current directory. 133 */ 134 if (geteuid() == 0 || getuid() == 0) { 135 if (__xpg4 == 0) { /* not XPG4 */ 136 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 137 } else { /* XPG4 (CSPATH + /usr/sbin) */ 138 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:" 139 "/opt/SUNWspro/bin:/usr/sbin"; 140 } 141 } else { 142 if (__xpg4 == 0) { /* not XPG4 */ 143 pathstr = "/usr/ccs/bin:/usr/bin:"; 144 } else { /* XPG4 (CSPATH) */ 145 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 146 "/usr/bin:/opt/SUNWspro/bin:"; 147 } 148 } 149 } 150 cp = strchr(name, '/')? (const char *)"": pathstr; 151 152 do { 153 cp = execat(cp, name, fname); 154 retry: 155 /* 156 * 4025035 and 4038378 157 * if a filename begins with a "-" prepend "./" so that 158 * the shell can't interpret it as an option 159 */ 160 if (*fname == '-') { 161 size_t size = strlen(fname) + 1; 162 if ((size + 2) > sizeof (fname)) { 163 errno = E2BIG; 164 return (-1); 165 } 166 (void) memmove(fname + 2, fname, size); 167 fname[0] = '.'; 168 fname[1] = '/'; 169 } 170 if (use_env) { 171 (void) execve(fname, argv, envp); 172 } else { 173 (void) execv(fname, argv); 174 } 175 switch (errno) { 176 case ENOEXEC: 177 newargs[0] = "sh"; 178 newargs[1] = fname; 179 for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) { 180 if (i >= 254) { 181 errno = E2BIG; 182 return (-1); 183 } 184 } 185 if (use_env) { 186 (void) execve(_PATH_BSHELL, newargs, envp); 187 } else { 188 (void) execv(_PATH_BSHELL, newargs); 189 } 190 return (-1); 191 case ETXTBSY: 192 if (++etxtbsy > 5) 193 return (-1); 194 (void) sleep(etxtbsy); 195 goto retry; 196 case EACCES: 197 ++eacces; 198 break; 199 case ENOMEM: 200 case E2BIG: 201 case EFAULT: 202 return (-1); 203 } 204 } while (cp); 205 if (eacces) 206 errno = EACCES; 207 return (-1); 208 } 209 210 int 211 execvp(const char *file, char *const *argv) 212 { 213 return (execvpe_int(file, argv, NULL, B_FALSE)); 214 } 215 216 int 217 execvpe(const char *file, char *const *argv, char *const *envp) 218 { 219 return (execvpe_int(file, argv, envp, B_TRUE)); 220 } 221 222 static const char * 223 execat(const char *s1, const char *s2, char *si) 224 { 225 char *s; 226 int cnt = PATH_MAX + 1; /* number of characters in s2 */ 227 228 s = si; 229 while (*s1 && *s1 != ':') { 230 if (cnt > 0) { 231 *s++ = *s1++; 232 cnt--; 233 } else 234 s1++; 235 } 236 if (si != s && cnt > 0) { 237 *s++ = '/'; 238 cnt--; 239 } 240 while (*s2 && cnt > 0) { 241 *s++ = *s2++; 242 cnt--; 243 } 244 *s = '\0'; 245 return (*s1 ? ++s1: 0); 246 } 247