Back to home page

OSCL-LXR

 
 

    


0001 /* Copyright (C) 2006 by Paolo Giarrusso - modified from glibc' execvp.c.
0002    Original copyright notice follows:
0003 
0004    Copyright (C) 1991,92,1995-99,2002,2004 Free Software Foundation, Inc.
0005    This file is part of the GNU C Library.
0006 
0007    The GNU C Library is free software; you can redistribute it and/or
0008    modify it under the terms of the GNU Lesser General Public
0009    License as published by the Free Software Foundation; either
0010    version 2.1 of the License, or (at your option) any later version.
0011 
0012    The GNU C Library is distributed in the hope that it will be useful,
0013    but WITHOUT ANY WARRANTY; without even the implied warranty of
0014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015    Lesser General Public License for more details.
0016 
0017    You should have received a copy of the GNU Lesser General Public
0018    License along with the GNU C Library; if not, write to the Free
0019    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
0020    02111-1307 USA.  */
0021 #include <unistd.h>
0022 
0023 #include <stdbool.h>
0024 #include <stdlib.h>
0025 #include <string.h>
0026 #include <errno.h>
0027 #include <limits.h>
0028 
0029 #ifndef TEST
0030 #include <um_malloc.h>
0031 #else
0032 #include <stdio.h>
0033 #define um_kmalloc malloc
0034 #endif
0035 #include <os.h>
0036 
0037 /* Execute FILE, searching in the `PATH' environment variable if it contains
0038    no slashes, with arguments ARGV and environment from `environ'.  */
0039 int execvp_noalloc(char *buf, const char *file, char *const argv[])
0040 {
0041     if (*file == '\0') {
0042         return -ENOENT;
0043     }
0044 
0045     if (strchr (file, '/') != NULL) {
0046         /* Don't search when it contains a slash.  */
0047         execv(file, argv);
0048     } else {
0049         int got_eacces;
0050         size_t len, pathlen;
0051         char *name, *p;
0052         char *path = getenv("PATH");
0053         if (path == NULL)
0054             path = ":/bin:/usr/bin";
0055 
0056         len = strlen(file) + 1;
0057         pathlen = strlen(path);
0058         /* Copy the file name at the top.  */
0059         name = memcpy(buf + pathlen + 1, file, len);
0060         /* And add the slash.  */
0061         *--name = '/';
0062 
0063         got_eacces = 0;
0064         p = path;
0065         do {
0066             char *startp;
0067 
0068             path = p;
0069             //Let's avoid this GNU extension.
0070             //p = strchrnul (path, ':');
0071             p = strchr(path, ':');
0072             if (!p)
0073                 p = strchr(path, '\0');
0074 
0075             if (p == path)
0076                 /* Two adjacent colons, or a colon at the beginning or the end
0077                    of `PATH' means to search the current directory.  */
0078                 startp = name + 1;
0079             else
0080                 startp = memcpy(name - (p - path), path, p - path);
0081 
0082             /* Try to execute this name.  If it works, execv will not return.  */
0083             execv(startp, argv);
0084 
0085             /*
0086             if (errno == ENOEXEC) {
0087             }
0088             */
0089 
0090             switch (errno) {
0091                 case EACCES:
0092                     /* Record the we got a `Permission denied' error.  If we end
0093                        up finding no executable we can use, we want to diagnose
0094                        that we did find one but were denied access.  */
0095                     got_eacces = 1;
0096                     break;
0097                 case ENOENT:
0098                 case ESTALE:
0099                 case ENOTDIR:
0100                     /* Those errors indicate the file is missing or not executable
0101                        by us, in which case we want to just try the next path
0102                        directory.  */
0103                 case ENODEV:
0104                 case ETIMEDOUT:
0105                     /* Some strange filesystems like AFS return even
0106                        stranger error numbers.  They cannot reasonably mean
0107                        anything else so ignore those, too.  */
0108                 case ENOEXEC:
0109                     /* We won't go searching for the shell
0110                      * if it is not executable - the Linux
0111                      * kernel already handles this enough,
0112                      * for us. */
0113                     break;
0114 
0115                 default:
0116                     /* Some other error means we found an executable file, but
0117                        something went wrong executing it; return the error to our
0118                        caller.  */
0119                     return -errno;
0120             }
0121         } while (*p++ != '\0');
0122 
0123         /* We tried every element and none of them worked.  */
0124         if (got_eacces)
0125             /* At least one failure was due to permissions, so report that
0126                error.  */
0127             return -EACCES;
0128     }
0129 
0130     /* Return the error from the last attempt (probably ENOENT).  */
0131     return -errno;
0132 }
0133 #ifdef TEST
0134 int main(int argc, char**argv)
0135 {
0136     char buf[PATH_MAX];
0137     int ret;
0138     argc--;
0139     if (!argc) {
0140         os_warn("Not enough arguments\n");
0141         return 1;
0142     }
0143     argv++;
0144     if (ret = execvp_noalloc(buf, argv[0], argv)) {
0145         errno = -ret;
0146         perror("execvp_noalloc");
0147     }
0148     return 0;
0149 }
0150 #endif