linux/arch/um/os-Linux/execvp.c
<<
>>
Prefs
   1/* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c.
   2   Original copyright notice follows:
   3
   4   Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc.
   5   This file is part of the GNU C Library.
   6
   7   The GNU C Library is free software; you can redistribute it and/or
   8   modify it under the terms of the GNU Lesser General Public
   9   License as published by the Free Software Foundation; either
  10   version 2.1 of the License, or (at your option) any later version.
  11
  12   The GNU C Library is distributed in the hope that it will be useful,
  13   but WITHOUT ANY WARRANTY; without even the implied warranty of
  14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15   Lesser General Public License for more details.
  16
  17   You should have received a copy of the GNU Lesser General Public
  18   License along with the GNU C Library; if not, write to the Free
  19   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  20   02111-1307 USA.  */
  21#include <unistd.h>
  22
  23#include <stdbool.h>
  24#include <stdlib.h>
  25#include <string.h>
  26#include <errno.h>
  27#include <limits.h>
  28
  29#ifndef TEST
  30#include <um_malloc.h>
  31#else
  32#include <stdio.h>
  33#define um_kmalloc malloc
  34#endif
  35#include <os.h>
  36
  37/* Execute FILE, searching in the `PATH' environment variable if it contains
  38   no slashes, with arguments ARGV and environment from `environ'.  */
  39int execvp_noalloc(char *buf, const char *file, char *const argv[])
  40{
  41        if (*file == '\0') {
  42                return -ENOENT;
  43        }
  44
  45        if (strchr (file, '/') != NULL) {
  46                /* Don't search when it contains a slash.  */
  47                execv(file, argv);
  48        } else {
  49                int got_eacces;
  50                size_t len, pathlen;
  51                char *name, *p;
  52                char *path = getenv("PATH");
  53                if (path == NULL)
  54                        path = ":/bin:/usr/bin";
  55
  56                len = strlen(file) + 1;
  57                pathlen = strlen(path);
  58                /* Copy the file name at the top.  */
  59                name = memcpy(buf + pathlen + 1, file, len);
  60                /* And add the slash.  */
  61                *--name = '/';
  62
  63                got_eacces = 0;
  64                p = path;
  65                do {
  66                        char *startp;
  67
  68                        path = p;
  69                        //Let's avoid this GNU extension.
  70                        //p = strchrnul (path, ':');
  71                        p = strchr(path, ':');
  72                        if (!p)
  73                                p = strchr(path, '\0');
  74
  75                        if (p == path)
  76                                /* Two adjacent colons, or a colon at the beginning or the end
  77                                   of `PATH' means to search the current directory.  */
  78                                startp = name + 1;
  79                        else
  80                                startp = memcpy(name - (p - path), path, p - path);
  81
  82                        /* Try to execute this name.  If it works, execv will not return.  */
  83                        execv(startp, argv);
  84
  85                        /*
  86                        if (errno == ENOEXEC) {
  87                        }
  88                        */
  89
  90                        switch (errno) {
  91                                case EACCES:
  92                                        /* Record the we got a `Permission denied' error.  If we end
  93                                           up finding no executable we can use, we want to diagnose
  94                                           that we did find one but were denied access.  */
  95                                        got_eacces = 1;
  96                                case ENOENT:
  97                                case ESTALE:
  98                                case ENOTDIR:
  99                                        /* Those errors indicate the file is missing or not executable
 100                                           by us, in which case we want to just try the next path
 101                                           directory.  */
 102                                case ENODEV:
 103                                case ETIMEDOUT:
 104                                        /* Some strange filesystems like AFS return even
 105                                           stranger error numbers.  They cannot reasonably mean
 106                                           anything else so ignore those, too.  */
 107                                case ENOEXEC:
 108                                        /* We won't go searching for the shell
 109                                         * if it is not executable - the Linux
 110                                         * kernel already handles this enough,
 111                                         * for us. */
 112                                        break;
 113
 114                                default:
 115                                        /* Some other error means we found an executable file, but
 116                                           something went wrong executing it; return the error to our
 117                                           caller.  */
 118                                        return -errno;
 119                        }
 120                } while (*p++ != '\0');
 121
 122                /* We tried every element and none of them worked.  */
 123                if (got_eacces)
 124                        /* At least one failure was due to permissions, so report that
 125                           error.  */
 126                        return -EACCES;
 127        }
 128
 129        /* Return the error from the last attempt (probably ENOENT).  */
 130        return -errno;
 131}
 132#ifdef TEST
 133int main(int argc, char**argv)
 134{
 135        char buf[PATH_MAX];
 136        int ret;
 137        argc--;
 138        if (!argc) {
 139                os_warn("Not enough arguments\n");
 140                return 1;
 141        }
 142        argv++;
 143        if (ret = execvp_noalloc(buf, argv[0], argv)) {
 144                errno = -ret;
 145                perror("execvp_noalloc");
 146        }
 147        return 0;
 148}
 149#endif
 150