reverse order to easily support variadic arguments. Thus, instead of using the proper stdarg.h macros (that nowadays are compiler-dependent), it may be tempting to directly take the address of the last argument and considering it as the start of an array. This is a shortcut that avoid looping to get all the arguments as the CPU already pushed them on the stack before the call to the function. Unfortunately, such an assumption is strictly compiler-dependent and compilers are free to move the last argument on the stack, as a local variable, and return the address of the location where the argument was stored, if asked for. This will break things as the rest of the array's argument are stored elsewhere (typically, a couple of words above the location where the argument was stored). This patch fixes the issue by allowing ACK to take the shortcut and enabling gcc/llvm-gcc to follow the right way.
73 lines
1.9 KiB
C
73 lines
1.9 KiB
C
/* execvp() - execute with PATH search and prepared arguments
|
|
* Author: Kees J. Bot
|
|
* 21 Jan 1994
|
|
*/
|
|
|
|
#define _MINIX_SOURCE
|
|
|
|
#define execve _execve
|
|
#define execvp _execvp
|
|
#define sbrk _sbrk
|
|
#define stat _stat
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
#include <sys/stat.h>
|
|
#include <lib.h>
|
|
|
|
extern char * const **_penviron; /* The default environment. */
|
|
|
|
int execvp(const char *file, char * const *argv)
|
|
/* Execute the file with a path search on $PATH, just like the shell. The
|
|
* search continues on the errors ENOENT (not there), and EACCES (file not
|
|
* executable or leading directories protected.)
|
|
* Unlike other execvp implementations there is no default path, and no shell
|
|
* is started for scripts. One is supposed to define $PATH, and use #!/bin/sh.
|
|
*/
|
|
{
|
|
struct stat sb;
|
|
const char *path; /* $PATH */
|
|
char *full; /* Full name to try. */
|
|
char *f;
|
|
size_t full_size;
|
|
int err= ENOENT; /* Error return on failure. */
|
|
|
|
if (strchr(file, '/') != NULL || (path= getenv("PATH")) == NULL)
|
|
path= "";
|
|
|
|
/* Compute the maximum length the full name may have, and align. */
|
|
full_size= strlen(path) + 1 + strlen(file) + 1 + sizeof(char *) - 1;
|
|
full_size&= ~(sizeof(char *) - 1);
|
|
|
|
/* Claim space. */
|
|
if ((full= (char *) sbrk(full_size)) == (char *) -1) {
|
|
errno= E2BIG;
|
|
return -1;
|
|
}
|
|
|
|
/* For each directory in the path... */
|
|
do {
|
|
f= full;
|
|
while (*path != 0 && *path != ':') *f++= *path++;
|
|
|
|
if (f > full) *f++= '/';
|
|
|
|
strcpy(f, file);
|
|
|
|
/* Stat first, small speed-up, better for ptrace. */
|
|
if (stat(full, &sb) == -1) continue;
|
|
|
|
(void) execve(full, argv, *_penviron);
|
|
|
|
/* Prefer more interesting errno values then "not there". */
|
|
if (errno != ENOENT) err= errno;
|
|
|
|
/* Continue only on some errors. */
|
|
if (err != ENOENT && err != EACCES) break;
|
|
} while (*path++ != 0);
|
|
|
|
(void) sbrk(-full_size);
|
|
errno= err;
|
|
return -1;
|
|
}
|