chiark / gitweb /
add "Persistent Device Naming" rules file for disks
[elogind.git] / klibc / klibc / execvpe.c
1 /*
2  * execvpe.c
3  *
4  * execvpe() function (from which we build execlp, execlpe, execvp).
5  *
6  * This version of execvpe() will *not* spawn /bin/sh if the command
7  * return ENOEXEC.  That's what #! is for, folks!
8  *
9  * Since execlpe() and execvpe() aren't in POSIX, nor in glibc,
10  * I have followed QNX precedent in the implementation of the PATH:
11  * the PATH that is used is the one in the current environment, not
12  * in the new environment.  Otherwise it would be impossible to pass
13  * a different PATH to the new process than the one one would want to
14  * use to search.
15  */
16
17 #include <errno.h>
18 #include <unistd.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <limits.h>
22
23 #define DEFAULT_PATH    "/bin:/usr/bin:."
24
25 int execvpe(const char *file, char * const *argv, char * const *envp)
26 {
27   char path[PATH_MAX];
28   const char *searchpath, *esp;
29   size_t prefixlen, filelen, totallen;
30
31   if ( strchr(file, '/') )      /* Specific path */
32     return execve(file, argv, envp);
33
34   filelen = strlen(file);
35
36   searchpath = getenv("PATH");
37   if ( !searchpath )
38     searchpath = DEFAULT_PATH;
39   
40   errno = ENOENT; /* Default errno, if execve() doesn't change it */
41
42   do {
43     esp = strchr(searchpath, ':');
44     if ( esp )
45       prefixlen = esp-searchpath;
46     else
47       prefixlen = strlen(searchpath);
48     
49     if ( prefixlen == 0 || searchpath[prefixlen-1] == '/' ) {
50       totallen = prefixlen+filelen;
51       if ( totallen >= PATH_MAX )
52         continue;
53       memcpy(path, searchpath, prefixlen);
54       memcpy(path+prefixlen, file, filelen);
55     } else {
56       totallen = prefixlen+filelen+1;
57       if ( totallen >= PATH_MAX )
58         continue;
59       memcpy(path, searchpath, prefixlen);
60       path[prefixlen] = '/';
61       memcpy(path+prefixlen+1, file, filelen);
62     }
63     path[totallen] = '\0';
64     
65     execve(path, argv, envp);
66     if ( errno == E2BIG || errno == ENOEXEC ||
67          errno == ENOMEM || errno == ETXTBSY )
68       break;                    /* Report this as an error, no more search */
69     
70     searchpath = esp+1;
71   } while ( esp );
72
73   return -1;
74 }
75