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 */ 26 27 /* Copyright (c) 1988 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * execlp(name, arg,...,0) (like execl, but does path search) 32 * execvp(name, argv) (like execv, but does path search) 33 */ 34 35 #pragma weak _execlp = execlp 36 #pragma weak _execvp = execvp 37 38 #include "lint.h" 39 #include <sys/types.h> 40 #include <unistd.h> 41 #include <string.h> 42 #include <alloca.h> 43 #include <errno.h> 44 #include <limits.h> 45 #include <stdarg.h> 46 #include <stdlib.h> 47 #include <paths.h> 48 49 static const char *execat(const char *, const char *, char *); 50 51 extern int __xpg4; /* defined in xpg4.c; 0 if not xpg4-compiled program */ 52 53 /*VARARGS1*/ 54 int 55 execlp(const char *name, const char *arg0, ...) 56 { 57 char **argp; 58 va_list args; 59 char **argvec; 60 int err; 61 int nargs = 0; 62 char *nextarg; 63 64 /* 65 * count the number of arguments in the variable argument list 66 * and allocate an argument vector for them on the stack, 67 * adding space for a terminating null pointer at the end 68 * and one additional space for argv[0] which is no longer 69 * counted by the varargs loop. 70 */ 71 72 va_start(args, arg0); 73 74 while (va_arg(args, char *) != (char *)0) 75 nargs++; 76 77 va_end(args); 78 79 /* 80 * load the arguments in the variable argument list 81 * into the argument vector and add the terminating null pointer 82 */ 83 84 va_start(args, arg0); 85 /* workaround for bugid 1242839 */ 86 argvec = alloca((size_t)((nargs + 2) * sizeof (char *))); 87 nextarg = va_arg(args, char *); 88 argp = argvec; 89 *argp++ = (char *)arg0; 90 while (nargs-- && nextarg != (char *)0) { 91 *argp = nextarg; 92 argp++; 93 nextarg = va_arg(args, char *); 94 } 95 va_end(args); 96 *argp = (char *)0; 97 98 /* 99 * call execvp() 100 */ 101 102 err = execvp(name, argvec); 103 return (err); 104 } 105 106 int 107 execvp(const char *name, char *const *argv) 108 { 109 const char *pathstr; 110 char fname[PATH_MAX+2]; 111 char *newargs[256]; 112 int i; 113 const char *cp; 114 unsigned etxtbsy = 1; 115 int eacces = 0; 116 117 if (*name == '\0') { 118 errno = ENOENT; 119 return (-1); 120 } 121 if ((pathstr = getenv("PATH")) == NULL) { 122 /* 123 * XPG4: pathstr is equivalent to CSPATH, except that 124 * :/usr/sbin is appended when root, and pathstr must end 125 * with a colon when not root. Keep these paths in sync 126 * with CSPATH in confstr.c. Note that pathstr must end 127 * with a colon when not root so that when name doesn't 128 * contain '/', the last call to execat() will result in an 129 * attempt to execv name from the current directory. 130 */ 131 if (geteuid() == 0 || getuid() == 0) { 132 if (__xpg4 == 0) { /* not XPG4 */ 133 pathstr = "/usr/sbin:/usr/ccs/bin:/usr/bin"; 134 } else { /* XPG4 (CSPATH + /usr/sbin) */ 135 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:/usr/bin:" 136 "/opt/SUNWspro/bin:/usr/sbin"; 137 } 138 } else { 139 if (__xpg4 == 0) { /* not XPG4 */ 140 pathstr = "/usr/ccs/bin:/usr/bin:"; 141 } else { /* XPG4 (CSPATH) */ 142 pathstr = "/usr/xpg4/bin:/usr/ccs/bin:" 143 "/usr/bin:/opt/SUNWspro/bin:"; 144 } 145 } 146 } 147 cp = strchr(name, '/')? (const char *)"": pathstr; 148 149 do { 150 cp = execat(cp, name, fname); 151 retry: 152 /* 153 * 4025035 and 4038378 154 * if a filename begins with a "-" prepend "./" so that 155 * the shell can't interpret it as an option 156 */ 157 if (*fname == '-') { 158 size_t size = strlen(fname) + 1; 159 if ((size + 2) > sizeof (fname)) { 160 errno = E2BIG; 161 return (-1); 162 } 163 (void) memmove(fname + 2, fname, size); 164 fname[0] = '.'; 165 fname[1] = '/'; 166 } 167 (void) execv(fname, argv); 168 switch (errno) { 169 case ENOEXEC: 170 newargs[0] = "sh"; 171 newargs[1] = fname; 172 for (i = 1; (newargs[i + 1] = argv[i]) != NULL; ++i) { 173 if (i >= 254) { 174 errno = E2BIG; 175 return (-1); 176 } 177 } 178 (void) execv(_PATH_BSHELL, newargs); 179 return (-1); 180 case ETXTBSY: 181 if (++etxtbsy > 5) 182 return (-1); 183 (void) sleep(etxtbsy); 184 goto retry; 185 case EACCES: 186 ++eacces; 187 break; 188 case ENOMEM: 189 case E2BIG: 190 case EFAULT: 191 return (-1); 192 } 193 } while (cp); 194 if (eacces) 195 errno = EACCES; 196 return (-1); 197 } 198 199 static const char * 200 execat(const char *s1, const char *s2, char *si) 201 { 202 char *s; 203 int cnt = PATH_MAX + 1; /* number of characters in s2 */ 204 205 s = si; 206 while (*s1 && *s1 != ':') { 207 if (cnt > 0) { 208 *s++ = *s1++; 209 cnt--; 210 } else 211 s1++; 212 } 213 if (si != s && cnt > 0) { 214 *s++ = '/'; 215 cnt--; 216 } 217 while (*s2 && cnt > 0) { 218 *s++ = *s2++; 219 cnt--; 220 } 221 *s = '\0'; 222 return (*s1 ? ++s1: 0); 223 } 224