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