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