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
execlp(const char * name,const char * arg0,...)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
execvp(const char * name,char * const * argv)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 *
execat(const char * s1,const char * s2,char * si)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