Merge branch 'topic/snd-hrtimer' into to-push
[linux-2.6] / arch / um / os-Linux / execvp.c
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'.  */
39 int 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
133 int main(int argc, char**argv)
134 {
135         char buf[PATH_MAX];
136         int ret;
137         argc--;
138         if (!argc) {
139                 fprintf(stderr, "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