Make improvements

- You can now run `make -j8 toolchain` on Windows
- You can now run `make -j` on MacOS ARM64 and BSD OSes
- You can now use our Emacs dev environment on MacOS/Windows
- Fix bug where the x16 register was being corrupted by --ftrace
- The programs under build/bootstrap/ are updated as fat binaries
- The Makefile now explains how to download cosmocc-0.0.12 toolchain
- The build scripts under bin/ now support "cosmo" branded toolchains
- stat() now goes faster on Windows (shaves 100ms off `make` latency)
- Code cleanup and added review on the Windows signal checking code
- posix_spawnattr_setrlimit() now works around MacOS ARM64 bugs
- Landlock Make now favors posix_spawn() on non-Linux/OpenBSD
- posix_spawn() now has better --strace logging on Windows
- fstatat() can now avoid EACCES in more cases on Windows
- fchmod() can now change the readonly bit on Windows
This commit is contained in:
Justine Tunney 2023-10-14 20:57:15 -07:00
parent 06c6baaf50
commit c9fecf3a55
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
109 changed files with 1188 additions and 454 deletions

View file

@ -20,6 +20,9 @@
#include "libc/errno.h"
#include "libc/str/str.h"
#include "libc/mem/mem.h"
#include "third_party/make/filename.h"
#include "libc/calls/struct/stat.h"
#include "libc/sysv/consts/s.h"
#include "third_party/make/config.h"
/* Specification. */
@ -58,8 +61,8 @@ static const char * const suffixes[] =
/* Note: The cmd.exe program does a different lookup: It searches according
to the PATHEXT environment variable.
See <https://stackoverflow.com/questions/7839150/>.
Also, it executes files ending .bat and .cmd directly without letting the
kernel interpret the program file. */
Also, it executes files ending in .bat and .cmd directly without letting
the kernel interpret the program file. */
#elif defined __CYGWIN__
"", ".exe", ".com"
#elif defined __EMX__
@ -73,7 +76,7 @@ static const char * const suffixes[] =
const char *
find_in_given_path (const char *progname, const char *path,
bool optimize_for_exec)
const char *directory, bool optimize_for_exec)
{
{
bool has_slash = false;
@ -101,6 +104,12 @@ find_in_given_path (const char *progname, const char *path,
with such a suffix is actually executable. */
int failure_errno;
size_t i;
const char *directory_as_prefix =
(directory != NULL && IS_RELATIVE_FILE_NAME (progname)
? directory
: "");
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
const char *progbasename;
@ -112,6 +121,8 @@ find_in_given_path (const char *progname, const char *path,
if (ISSLASH (*p))
progbasename = p + 1;
}
bool progbasename_has_dot = (strchr (progbasename, '.') != NULL);
#endif
/* Try all platform-dependent suffixes. */
@ -123,12 +134,16 @@ find_in_given_path (const char *progname, const char *path,
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
/* File names without a '.' are not considered executable, and
for file names with a '.' no additional suffix is tried. */
if ((*suffix != '\0') != (strchr (progbasename, '.') != NULL))
if ((*suffix != '\0') != progbasename_has_dot)
#endif
{
/* Concatenate progname and suffix. */
/* Concatenate directory_as_prefix, progname, suffix. */
char *progpathname =
xconcatenated_filename ("", progname, suffix);
concatenated_filename (directory_as_prefix, progname,
suffix);
if (progpathname == NULL)
return NULL; /* errno is set here */
/* On systems which have the eaccess() system call, let's
use it. On other systems, let's hope that this program
@ -136,14 +151,26 @@ find_in_given_path (const char *progname, const char *path,
call access() despite its design flaw. */
if (eaccess (progpathname, X_OK) == 0)
{
/* Found! */
if (strcmp (progpathname, progname) == 0)
/* Check that the progpathname does not point to a
directory. */
struct stat statbuf;
if (stat (progpathname, &statbuf) >= 0)
{
free (progpathname);
return progname;
if (! S_ISDIR (statbuf.st_mode))
{
/* Found! */
if (strcmp (progpathname, progname) == 0)
{
free (progpathname);
return progname;
}
else
return progpathname;
}
errno = EACCES;
}
else
return progpathname;
}
if (errno != ENOENT)
@ -152,6 +179,36 @@ find_in_given_path (const char *progname, const char *path,
free (progpathname);
}
}
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
if (failure_errno == ENOENT && !progbasename_has_dot)
{
/* In the loop above, we skipped suffix = "". Do this loop
round now, merely to provide a better errno than ENOENT. */
char *progpathname =
concatenated_filename (directory_as_prefix, progname, "");
if (progpathname == NULL)
return NULL; /* errno is set here */
if (eaccess (progpathname, X_OK) == 0)
{
struct stat statbuf;
if (stat (progpathname, &statbuf) >= 0)
{
if (! S_ISDIR (statbuf.st_mode))
errno = ENOEXEC;
else
errno = EACCES;
}
}
failure_errno = errno;
free (progpathname);
}
#endif
errno = failure_errno;
return NULL;
@ -165,17 +222,26 @@ find_in_given_path (const char *progname, const char *path,
path = "";
{
int failure_errno;
/* Make a copy, to prepare for destructive modifications. */
char *path_copy = xstrdup (path);
char *path_copy = strdup (path);
if (path_copy == NULL)
return NULL; /* errno is set here */
int failure_errno;
char *path_rest;
char *cp;
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
bool progname_has_dot = (strchr (progname, '.') != NULL);
#endif
failure_errno = ENOENT;
for (path_rest = path_copy; ; path_rest = cp + 1)
{
const char *dir;
bool last;
char *dir_as_prefix_to_free;
const char *dir_as_prefix;
size_t i;
/* Extract next directory in PATH. */
@ -189,6 +255,25 @@ find_in_given_path (const char *progname, const char *path,
if (dir == cp)
dir = ".";
/* Concatenate directory and dir. */
if (directory != NULL && IS_RELATIVE_FILE_NAME (dir))
{
dir_as_prefix_to_free =
concatenated_filename (directory, dir, NULL);
if (dir_as_prefix_to_free == NULL)
{
/* errno is set here. */
failure_errno = errno;
goto failed;
}
dir_as_prefix = dir_as_prefix_to_free;
}
else
{
dir_as_prefix_to_free = NULL;
dir_as_prefix = dir;
}
/* Try all platform-dependent suffixes. */
for (i = 0; i < sizeof (suffixes) / sizeof (suffixes[0]); i++)
{
@ -197,12 +282,20 @@ find_in_given_path (const char *progname, const char *path,
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
/* File names without a '.' are not considered executable, and
for file names with a '.' no additional suffix is tried. */
if ((*suffix != '\0') != (strchr (progname, '.') != NULL))
if ((*suffix != '\0') != progname_has_dot)
#endif
{
/* Concatenate dir, progname, and suffix. */
/* Concatenate dir_as_prefix, progname, and suffix. */
char *progpathname =
xconcatenated_filename (dir, progname, suffix);
concatenated_filename (dir_as_prefix, progname, suffix);
if (progpathname == NULL)
{
/* errno is set here. */
failure_errno = errno;
free (dir_as_prefix_to_free);
goto failed;
}
/* On systems which have the eaccess() system call, let's
use it. On other systems, let's hope that this program
@ -210,25 +303,45 @@ find_in_given_path (const char *progname, const char *path,
call access() despite its design flaw. */
if (eaccess (progpathname, X_OK) == 0)
{
/* Found! */
if (strcmp (progpathname, progname) == 0)
/* Check that the progpathname does not point to a
directory. */
struct stat statbuf;
if (stat (progpathname, &statbuf) >= 0)
{
free (progpathname);
if (! S_ISDIR (statbuf.st_mode))
{
/* Found! */
if (strcmp (progpathname, progname) == 0)
{
free (progpathname);
/* Add the "./" prefix for real, that
xconcatenated_filename() optimized away. This
avoids a second PATH search when the caller uses
execl/execv/execlp/execvp. */
progpathname =
XNMALLOC (2 + strlen (progname) + 1, char);
progpathname[0] = '.';
progpathname[1] = NATIVE_SLASH;
memcpy (progpathname + 2, progname,
strlen (progname) + 1);
/* Add the "./" prefix for real, that
concatenated_filename() optimized away.
This avoids a second PATH search when the
caller uses execl/execv/execlp/execvp. */
progpathname =
(char *) malloc (2 + strlen (progname) + 1);
if (progpathname == NULL)
{
/* errno is set here. */
failure_errno = errno;
free (dir_as_prefix_to_free);
goto failed;
}
progpathname[0] = '.';
progpathname[1] = NATIVE_SLASH;
memcpy (progpathname + 2, progname,
strlen (progname) + 1);
}
free (dir_as_prefix_to_free);
free (path_copy);
return progpathname;
}
errno = EACCES;
}
free (path_copy);
return progpathname;
}
if (errno != ENOENT)
@ -237,11 +350,49 @@ find_in_given_path (const char *progname, const char *path,
free (progpathname);
}
}
#if defined _WIN32 && !defined __CYGWIN__ /* Native Windows */
if (failure_errno == ENOENT && !progname_has_dot)
{
/* In the loop above, we skipped suffix = "". Do this loop
round now, merely to provide a better errno than ENOENT. */
char *progpathname =
concatenated_filename (dir_as_prefix, progname, "");
if (progpathname == NULL)
{
/* errno is set here. */
failure_errno = errno;
free (dir_as_prefix_to_free);
goto failed;
}
if (eaccess (progpathname, X_OK) == 0)
{
struct stat statbuf;
if (stat (progpathname, &statbuf) >= 0)
{
if (! S_ISDIR (statbuf.st_mode))
errno = ENOEXEC;
else
errno = EACCES;
}
}
failure_errno = errno;
free (progpathname);
}
#endif
free (dir_as_prefix_to_free);
if (last)
break;
}
failed:
/* Not found in PATH. */
free (path_copy);