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