xref: /openbmc/linux/arch/um/os-Linux/execvp.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
15d48545eSPaolo 'Blaisorblade' Giarrusso /* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c.
25d48545eSPaolo 'Blaisorblade' Giarrusso    Original copyright notice follows:
35d48545eSPaolo 'Blaisorblade' Giarrusso 
45d48545eSPaolo 'Blaisorblade' Giarrusso    Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc.
55d48545eSPaolo 'Blaisorblade' Giarrusso    This file is part of the GNU C Library.
65d48545eSPaolo 'Blaisorblade' Giarrusso 
75d48545eSPaolo 'Blaisorblade' Giarrusso    The GNU C Library is free software; you can redistribute it and/or
85d48545eSPaolo 'Blaisorblade' Giarrusso    modify it under the terms of the GNU Lesser General Public
95d48545eSPaolo 'Blaisorblade' Giarrusso    License as published by the Free Software Foundation; either
105d48545eSPaolo 'Blaisorblade' Giarrusso    version 2.1 of the License, or (at your option) any later version.
115d48545eSPaolo 'Blaisorblade' Giarrusso 
125d48545eSPaolo 'Blaisorblade' Giarrusso    The GNU C Library is distributed in the hope that it will be useful,
135d48545eSPaolo 'Blaisorblade' Giarrusso    but WITHOUT ANY WARRANTY; without even the implied warranty of
145d48545eSPaolo 'Blaisorblade' Giarrusso    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
155d48545eSPaolo 'Blaisorblade' Giarrusso    Lesser General Public License for more details.
165d48545eSPaolo 'Blaisorblade' Giarrusso 
175d48545eSPaolo 'Blaisorblade' Giarrusso    You should have received a copy of the GNU Lesser General Public
185d48545eSPaolo 'Blaisorblade' Giarrusso    License along with the GNU C Library; if not, write to the Free
195d48545eSPaolo 'Blaisorblade' Giarrusso    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
205d48545eSPaolo 'Blaisorblade' Giarrusso    02111-1307 USA.  */
215d48545eSPaolo 'Blaisorblade' Giarrusso #include <unistd.h>
225d48545eSPaolo 'Blaisorblade' Giarrusso 
235d48545eSPaolo 'Blaisorblade' Giarrusso #include <stdbool.h>
245d48545eSPaolo 'Blaisorblade' Giarrusso #include <stdlib.h>
255d48545eSPaolo 'Blaisorblade' Giarrusso #include <string.h>
265d48545eSPaolo 'Blaisorblade' Giarrusso #include <errno.h>
275d48545eSPaolo 'Blaisorblade' Giarrusso #include <limits.h>
285d48545eSPaolo 'Blaisorblade' Giarrusso 
295d48545eSPaolo 'Blaisorblade' Giarrusso #ifndef TEST
3037185b33SAl Viro #include <um_malloc.h>
315d48545eSPaolo 'Blaisorblade' Giarrusso #else
325d48545eSPaolo 'Blaisorblade' Giarrusso #include <stdio.h>
335d48545eSPaolo 'Blaisorblade' Giarrusso #define um_kmalloc malloc
345d48545eSPaolo 'Blaisorblade' Giarrusso #endif
3537185b33SAl Viro #include <os.h>
365d48545eSPaolo 'Blaisorblade' Giarrusso 
375d48545eSPaolo 'Blaisorblade' Giarrusso /* Execute FILE, searching in the `PATH' environment variable if it contains
385d48545eSPaolo 'Blaisorblade' Giarrusso    no slashes, with arguments ARGV and environment from `environ'.  */
execvp_noalloc(char * buf,const char * file,char * const argv[])395d48545eSPaolo 'Blaisorblade' Giarrusso int execvp_noalloc(char *buf, const char *file, char *const argv[])
405d48545eSPaolo 'Blaisorblade' Giarrusso {
415d48545eSPaolo 'Blaisorblade' Giarrusso 	if (*file == '\0') {
425d48545eSPaolo 'Blaisorblade' Giarrusso 		return -ENOENT;
435d48545eSPaolo 'Blaisorblade' Giarrusso 	}
445d48545eSPaolo 'Blaisorblade' Giarrusso 
455d48545eSPaolo 'Blaisorblade' Giarrusso 	if (strchr (file, '/') != NULL) {
465d48545eSPaolo 'Blaisorblade' Giarrusso 		/* Don't search when it contains a slash.  */
475d48545eSPaolo 'Blaisorblade' Giarrusso 		execv(file, argv);
485d48545eSPaolo 'Blaisorblade' Giarrusso 	} else {
495d48545eSPaolo 'Blaisorblade' Giarrusso 		int got_eacces;
505d48545eSPaolo 'Blaisorblade' Giarrusso 		size_t len, pathlen;
515d48545eSPaolo 'Blaisorblade' Giarrusso 		char *name, *p;
525d48545eSPaolo 'Blaisorblade' Giarrusso 		char *path = getenv("PATH");
535d48545eSPaolo 'Blaisorblade' Giarrusso 		if (path == NULL)
545d48545eSPaolo 'Blaisorblade' Giarrusso 			path = ":/bin:/usr/bin";
555d48545eSPaolo 'Blaisorblade' Giarrusso 
565d48545eSPaolo 'Blaisorblade' Giarrusso 		len = strlen(file) + 1;
575d48545eSPaolo 'Blaisorblade' Giarrusso 		pathlen = strlen(path);
585d48545eSPaolo 'Blaisorblade' Giarrusso 		/* Copy the file name at the top.  */
595d48545eSPaolo 'Blaisorblade' Giarrusso 		name = memcpy(buf + pathlen + 1, file, len);
605d48545eSPaolo 'Blaisorblade' Giarrusso 		/* And add the slash.  */
615d48545eSPaolo 'Blaisorblade' Giarrusso 		*--name = '/';
625d48545eSPaolo 'Blaisorblade' Giarrusso 
635d48545eSPaolo 'Blaisorblade' Giarrusso 		got_eacces = 0;
645d48545eSPaolo 'Blaisorblade' Giarrusso 		p = path;
655d48545eSPaolo 'Blaisorblade' Giarrusso 		do {
665d48545eSPaolo 'Blaisorblade' Giarrusso 			char *startp;
675d48545eSPaolo 'Blaisorblade' Giarrusso 
685d48545eSPaolo 'Blaisorblade' Giarrusso 			path = p;
695d48545eSPaolo 'Blaisorblade' Giarrusso 			//Let's avoid this GNU extension.
705d48545eSPaolo 'Blaisorblade' Giarrusso 			//p = strchrnul (path, ':');
715d48545eSPaolo 'Blaisorblade' Giarrusso 			p = strchr(path, ':');
725d48545eSPaolo 'Blaisorblade' Giarrusso 			if (!p)
735d48545eSPaolo 'Blaisorblade' Giarrusso 				p = strchr(path, '\0');
745d48545eSPaolo 'Blaisorblade' Giarrusso 
755d48545eSPaolo 'Blaisorblade' Giarrusso 			if (p == path)
765d48545eSPaolo 'Blaisorblade' Giarrusso 				/* Two adjacent colons, or a colon at the beginning or the end
775d48545eSPaolo 'Blaisorblade' Giarrusso 				   of `PATH' means to search the current directory.  */
785d48545eSPaolo 'Blaisorblade' Giarrusso 				startp = name + 1;
795d48545eSPaolo 'Blaisorblade' Giarrusso 			else
805d48545eSPaolo 'Blaisorblade' Giarrusso 				startp = memcpy(name - (p - path), path, p - path);
815d48545eSPaolo 'Blaisorblade' Giarrusso 
825d48545eSPaolo 'Blaisorblade' Giarrusso 			/* Try to execute this name.  If it works, execv will not return.  */
835d48545eSPaolo 'Blaisorblade' Giarrusso 			execv(startp, argv);
845d48545eSPaolo 'Blaisorblade' Giarrusso 
855d48545eSPaolo 'Blaisorblade' Giarrusso 			/*
865d48545eSPaolo 'Blaisorblade' Giarrusso 			if (errno == ENOEXEC) {
875d48545eSPaolo 'Blaisorblade' Giarrusso 			}
885d48545eSPaolo 'Blaisorblade' Giarrusso 			*/
895d48545eSPaolo 'Blaisorblade' Giarrusso 
905d48545eSPaolo 'Blaisorblade' Giarrusso 			switch (errno) {
915d48545eSPaolo 'Blaisorblade' Giarrusso 				case EACCES:
925d48545eSPaolo 'Blaisorblade' Giarrusso 					/* Record the we got a `Permission denied' error.  If we end
935d48545eSPaolo 'Blaisorblade' Giarrusso 					   up finding no executable we can use, we want to diagnose
945d48545eSPaolo 'Blaisorblade' Giarrusso 					   that we did find one but were denied access.  */
955d48545eSPaolo 'Blaisorblade' Giarrusso 					got_eacces = 1;
96*c7500c1bSKees Cook 					break;
975d48545eSPaolo 'Blaisorblade' Giarrusso 				case ENOENT:
985d48545eSPaolo 'Blaisorblade' Giarrusso 				case ESTALE:
995d48545eSPaolo 'Blaisorblade' Giarrusso 				case ENOTDIR:
1005d48545eSPaolo 'Blaisorblade' Giarrusso 					/* Those errors indicate the file is missing or not executable
1015d48545eSPaolo 'Blaisorblade' Giarrusso 					   by us, in which case we want to just try the next path
1025d48545eSPaolo 'Blaisorblade' Giarrusso 					   directory.  */
1035d48545eSPaolo 'Blaisorblade' Giarrusso 				case ENODEV:
1045d48545eSPaolo 'Blaisorblade' Giarrusso 				case ETIMEDOUT:
1055d48545eSPaolo 'Blaisorblade' Giarrusso 					/* Some strange filesystems like AFS return even
1065d48545eSPaolo 'Blaisorblade' Giarrusso 					   stranger error numbers.  They cannot reasonably mean
1075d48545eSPaolo 'Blaisorblade' Giarrusso 					   anything else so ignore those, too.  */
1085d48545eSPaolo 'Blaisorblade' Giarrusso 				case ENOEXEC:
1095d48545eSPaolo 'Blaisorblade' Giarrusso 					/* We won't go searching for the shell
1105d48545eSPaolo 'Blaisorblade' Giarrusso 					 * if it is not executable - the Linux
1115d48545eSPaolo 'Blaisorblade' Giarrusso 					 * kernel already handles this enough,
1125d48545eSPaolo 'Blaisorblade' Giarrusso 					 * for us. */
1135d48545eSPaolo 'Blaisorblade' Giarrusso 					break;
1145d48545eSPaolo 'Blaisorblade' Giarrusso 
1155d48545eSPaolo 'Blaisorblade' Giarrusso 				default:
1165d48545eSPaolo 'Blaisorblade' Giarrusso 					/* Some other error means we found an executable file, but
1175d48545eSPaolo 'Blaisorblade' Giarrusso 					   something went wrong executing it; return the error to our
1185d48545eSPaolo 'Blaisorblade' Giarrusso 					   caller.  */
1195d48545eSPaolo 'Blaisorblade' Giarrusso 					return -errno;
1205d48545eSPaolo 'Blaisorblade' Giarrusso 			}
1215d48545eSPaolo 'Blaisorblade' Giarrusso 		} while (*p++ != '\0');
1225d48545eSPaolo 'Blaisorblade' Giarrusso 
1235d48545eSPaolo 'Blaisorblade' Giarrusso 		/* We tried every element and none of them worked.  */
1245d48545eSPaolo 'Blaisorblade' Giarrusso 		if (got_eacces)
1255d48545eSPaolo 'Blaisorblade' Giarrusso 			/* At least one failure was due to permissions, so report that
1265d48545eSPaolo 'Blaisorblade' Giarrusso 			   error.  */
1275d48545eSPaolo 'Blaisorblade' Giarrusso 			return -EACCES;
1285d48545eSPaolo 'Blaisorblade' Giarrusso 	}
1295d48545eSPaolo 'Blaisorblade' Giarrusso 
1305d48545eSPaolo 'Blaisorblade' Giarrusso 	/* Return the error from the last attempt (probably ENOENT).  */
1315d48545eSPaolo 'Blaisorblade' Giarrusso 	return -errno;
1325d48545eSPaolo 'Blaisorblade' Giarrusso }
1335d48545eSPaolo 'Blaisorblade' Giarrusso #ifdef TEST
main(int argc,char ** argv)1345d48545eSPaolo 'Blaisorblade' Giarrusso int main(int argc, char**argv)
1355d48545eSPaolo 'Blaisorblade' Giarrusso {
1365d48545eSPaolo 'Blaisorblade' Giarrusso 	char buf[PATH_MAX];
1375d48545eSPaolo 'Blaisorblade' Giarrusso 	int ret;
1385d48545eSPaolo 'Blaisorblade' Giarrusso 	argc--;
1395d48545eSPaolo 'Blaisorblade' Giarrusso 	if (!argc) {
1400936d4f3SMasami Hiramatsu 		os_warn("Not enough arguments\n");
1415d48545eSPaolo 'Blaisorblade' Giarrusso 		return 1;
1425d48545eSPaolo 'Blaisorblade' Giarrusso 	}
1435d48545eSPaolo 'Blaisorblade' Giarrusso 	argv++;
1445d48545eSPaolo 'Blaisorblade' Giarrusso 	if (ret = execvp_noalloc(buf, argv[0], argv)) {
1455d48545eSPaolo 'Blaisorblade' Giarrusso 		errno = -ret;
1465d48545eSPaolo 'Blaisorblade' Giarrusso 		perror("execvp_noalloc");
1475d48545eSPaolo 'Blaisorblade' Giarrusso 	}
1485d48545eSPaolo 'Blaisorblade' Giarrusso 	return 0;
1495d48545eSPaolo 'Blaisorblade' Giarrusso }
1505d48545eSPaolo 'Blaisorblade' Giarrusso #endif
151