Home | History | Annotate | Download | only in gen
      1 /*	$OpenBSD: exec.c,v 1.21 2013/09/30 12:02:33 millert Exp $ */
      2 /*-
      3  * Copyright (c) 1991, 1993
      4  *	The Regents of the University of California.  All rights reserved.
      5  *
      6  * Redistribution and use in source and binary forms, with or without
      7  * modification, are permitted provided that the following conditions
      8  * are met:
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  * 3. Neither the name of the University nor the names of its contributors
     15  *    may be used to endorse or promote products derived from this software
     16  *    without specific prior written permission.
     17  *
     18  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     28  * SUCH DAMAGE.
     29  */
     30 
     31 #include <sys/types.h>
     32 #include <sys/uio.h>
     33 
     34 #include <errno.h>
     35 #include <limits.h>
     36 #include <paths.h>
     37 #include <stdarg.h>
     38 #include <stdio.h>
     39 #include <stdlib.h>
     40 #include <string.h>
     41 #include <unistd.h>
     42 
     43 extern char **environ;
     44 
     45 int
     46 execl(const char *name, const char *arg, ...)
     47 {
     48 	va_list ap;
     49 	char **argv;
     50 	int n;
     51 
     52 	va_start(ap, arg);
     53 	n = 1;
     54 	while (va_arg(ap, char *) != NULL)
     55 		n++;
     56 	va_end(ap);
     57 	argv = alloca((n + 1) * sizeof(*argv));
     58 	if (argv == NULL) {
     59 		errno = ENOMEM;
     60 		return (-1);
     61 	}
     62 	va_start(ap, arg);
     63 	n = 1;
     64 	argv[0] = (char *)arg;
     65 	while ((argv[n] = va_arg(ap, char *)) != NULL)
     66 		n++;
     67 	va_end(ap);
     68 	return (execve(name, argv, environ));
     69 }
     70 
     71 int
     72 execle(const char *name, const char *arg, ...)
     73 {
     74 	va_list ap;
     75 	char **argv, **envp;
     76 	int n;
     77 
     78 	va_start(ap, arg);
     79 	n = 1;
     80 	while (va_arg(ap, char *) != NULL)
     81 		n++;
     82 	va_end(ap);
     83 	argv = alloca((n + 1) * sizeof(*argv));
     84 	if (argv == NULL) {
     85 		errno = ENOMEM;
     86 		return (-1);
     87 	}
     88 	va_start(ap, arg);
     89 	n = 1;
     90 	argv[0] = (char *)arg;
     91 	while ((argv[n] = va_arg(ap, char *)) != NULL)
     92 		n++;
     93 	envp = va_arg(ap, char **);
     94 	va_end(ap);
     95 	return (execve(name, argv, envp));
     96 }
     97 
     98 int
     99 execlp(const char *name, const char *arg, ...)
    100 {
    101 	va_list ap;
    102 	char **argv;
    103 	int n;
    104 
    105 	va_start(ap, arg);
    106 	n = 1;
    107 	while (va_arg(ap, char *) != NULL)
    108 		n++;
    109 	va_end(ap);
    110 	argv = alloca((n + 1) * sizeof(*argv));
    111 	if (argv == NULL) {
    112 		errno = ENOMEM;
    113 		return (-1);
    114 	}
    115 	va_start(ap, arg);
    116 	n = 1;
    117 	argv[0] = (char *)arg;
    118 	while ((argv[n] = va_arg(ap, char *)) != NULL)
    119 		n++;
    120 	va_end(ap);
    121 	return (execvp(name, argv));
    122 }
    123 
    124 int
    125 execv(const char *name, char *const *argv)
    126 {
    127 	(void)execve(name, argv, environ);
    128 	return (-1);
    129 }
    130 
    131 int
    132 execvpe(const char *name, char *const *argv, char *const *envp)
    133 {
    134 	char **memp;
    135 	int cnt;
    136 	size_t lp, ln, len;
    137 	char *p;
    138 	int eacces = 0;
    139 	char *bp, *cur, *path, buf[PATH_MAX];
    140 
    141 	/*
    142 	 * Do not allow null name
    143 	 */
    144 	if (name == NULL || *name == '\0') {
    145 		errno = ENOENT;
    146 		return (-1);
    147  	}
    148 
    149 	/* If it's an absolute or relative path name, it's easy. */
    150 	if (strchr(name, '/')) {
    151 		bp = (char *)name;
    152 		cur = path = NULL;
    153 		goto retry;
    154 	}
    155 	bp = buf;
    156 
    157 	/* Get the path we're searching. */
    158 	if (!(path = getenv("PATH")))
    159 		path = _PATH_DEFPATH;
    160 	len = strlen(path) + 1;
    161 	cur = alloca(len);
    162 	if (cur == NULL) {
    163 		errno = ENOMEM;
    164 		return (-1);
    165 	}
    166 	strlcpy(cur, path, len);
    167 	path = cur;
    168 	while ((p = strsep(&cur, ":"))) {
    169 		/*
    170 		 * It's a SHELL path -- double, leading and trailing colons
    171 		 * mean the current directory.
    172 		 */
    173 		if (!*p) {
    174 			p = ".";
    175 			lp = 1;
    176 		} else
    177 			lp = strlen(p);
    178 		ln = strlen(name);
    179 
    180 		/*
    181 		 * If the path is too long complain.  This is a possible
    182 		 * security issue; given a way to make the path too long
    183 		 * the user may execute the wrong program.
    184 		 */
    185 		if (lp + ln + 2 > sizeof(buf)) {
    186 			struct iovec iov[3];
    187 
    188 			iov[0].iov_base = "execvp: ";
    189 			iov[0].iov_len = 8;
    190 			iov[1].iov_base = p;
    191 			iov[1].iov_len = lp;
    192 			iov[2].iov_base = ": path too long\n";
    193 			iov[2].iov_len = 16;
    194 			(void)writev(STDERR_FILENO, iov, 3);
    195 			continue;
    196 		}
    197 		bcopy(p, buf, lp);
    198 		buf[lp] = '/';
    199 		bcopy(name, buf + lp + 1, ln);
    200 		buf[lp + ln + 1] = '\0';
    201 
    202 retry:		(void)execve(bp, argv, envp);
    203 		switch(errno) {
    204 		case E2BIG:
    205 			goto done;
    206 		case EISDIR:
    207 		case ELOOP:
    208 		case ENAMETOOLONG:
    209 		case ENOENT:
    210 			break;
    211 		case ENOEXEC:
    212 			for (cnt = 0; argv[cnt]; ++cnt)
    213 				;
    214 			memp = alloca((cnt + 2) * sizeof(char *));
    215 			if (memp == NULL)
    216 				goto done;
    217 			memp[0] = "sh";
    218 			memp[1] = bp;
    219 			bcopy(argv + 1, memp + 2, cnt * sizeof(char *));
    220 			(void)execve(_PATH_BSHELL, memp, envp);
    221 			goto done;
    222 		case ENOMEM:
    223 			goto done;
    224 		case ENOTDIR:
    225 			break;
    226 		case ETXTBSY:
    227 			/*
    228 			 * We used to retry here, but sh(1) doesn't.
    229 			 */
    230 			goto done;
    231 		case EACCES:
    232 			eacces = 1;
    233 			break;
    234 		default:
    235 			goto done;
    236 		}
    237 	}
    238 	if (eacces)
    239 		errno = EACCES;
    240 	else if (!errno)
    241 		errno = ENOENT;
    242 done:
    243 	return (-1);
    244 }
    245 
    246 int
    247 execvp(const char *name, char *const *argv)
    248 {
    249     return execvpe(name, argv, environ);
    250 }
    251 
    252