![](https://secure.gravatar.com/avatar/df8330968b6df8cd1c1942c5fb4b720c.jpg?s=120&d=mm&r=g)
commit 984d837a9a265852e2fc646db99c59eb840c9692 Author: Juergen Daubert <jue@jue.li> Date: Fri Nov 18 11:19:59 2022 +0100 make: apply fixes from upstream as of 20221116 diff --git a/make/.signature b/make/.signature index e74f7acb..101f6b62 100644 --- a/make/.signature +++ b/make/.signature @@ -1,5 +1,6 @@ untrusted comment: verify with /etc/ports/core.pub -RWRJc1FUaeVeqlZ/6uv/CIc4J/jW+QCN38o65tbKuptSDLSR5rAY2P0cC4jol0r6oaGu3IMjqwUmEy/pmFC1PlKxn25p6BRl0As= -SHA256 (Pkgfile) = 6c353d7640034c7ab17d1b02ad9a45e177f4f0c56322019ae3d3e51959c5f49a +RWRJc1FUaeVeqoXDuWrY15k8jV1y1IY3Ub0XxrB+N87lSe5pXwzy47rX8pA5LUsLLuRF0sa2H44QCWhiKcQSS05fnQAxp2BEsQk= +SHA256 (Pkgfile) = 1ef61e26be47b2a6bc292ce327f90817d5f0c23689bf6a598a55e0dc37287200 SHA256 (.footprint) = b6da4d8d5f42687f723b196c608941bfe0f0211397dc663c56e43459f0c8be75 SHA256 (make-4.4.tar.lz) = 48d0fc0b2a04bb50f2911c16da65723285f7f4804c74fc5a2124a3df6c5f78c4 +SHA256 (upstream-fixes-20221116.patch) = d053aa03111bb4f49eb9d2c527b961fb53c608188883e3eb3d94c44f3e288391 diff --git a/make/Pkgfile b/make/Pkgfile index 2a440de2..bf928da9 100644 --- a/make/Pkgfile +++ b/make/Pkgfile @@ -4,11 +4,13 @@ name=make version=4.4 -release=1 -source=(https://ftpmirror.gnu.org/gnu/$name/$name-$version.tar.lz) +release=2 +source=(https://ftpmirror.gnu.org/gnu/$name/$name-$version.tar.lz + upstream-fixes-20221116.patch) build() { cd $name-$version + patch -p1 -i $SRC/upstream-fixes-20221116.patch ./configure --prefix=/usr --disable-nls make make DESTDIR=$PKG install diff --git a/make/upstream-fixes-20221116.patch b/make/upstream-fixes-20221116.patch new file mode 100644 index 00000000..a7db8087 --- /dev/null +++ b/make/upstream-fixes-20221116.patch @@ -0,0 +1,1213 @@ +diff --git a/src/config.h.W32 b/src/config.h.W32 +index 1a03a041..369e897d 100644 +--- a/src/config.h.W32 ++++ b/src/config.h.W32 +@@ -344,6 +344,14 @@ this program. If not, see <https://www.gnu.org/licenses/>. */ + + /* Define to 1 if you have the `strtoll' function. */ + #define HAVE_STRTOLL 1 ++#ifdef __TINYC__ ++# ifndef strtoll ++# define strtoll _strtoi64 ++# endif ++# ifndef strtoull ++# define strtoull _strtoui64 ++# endif ++#endif + + /* Define to 1 if `d_type' is a member of `struct dirent'. */ + /* SV 57152: MinGW64 version of dirent doesn't support d_type. */ +diff --git a/src/dir.c b/src/dir.c +index b47e94fe..1e6e7397 100644 +--- a/src/dir.c ++++ b/src/dir.c +@@ -456,7 +456,7 @@ dirfile_hash_cmp (const void *xv, const void *yv) + #define DIRFILE_BUCKETS 107 + #endif + +-static int dir_contents_file_exists_p (struct directory_contents *dir, ++static int dir_contents_file_exists_p (struct directory *dir, + const char *filename); + static struct directory *find_directory (const char *name); + +@@ -623,7 +623,7 @@ find_directory (const char *name) + if (open_directories == MAX_OPEN_DIRECTORIES) + /* We have too many directories open already. + Read the entire directory and then close it. */ +- dir_contents_file_exists_p (dc, 0); ++ dir_contents_file_exists_p (dir, 0); + } + } + +@@ -634,17 +634,18 @@ find_directory (const char *name) + FILENAME must contain no slashes. */ + + static int +-dir_contents_file_exists_p (struct directory_contents *dir, ++dir_contents_file_exists_p (struct directory *dir, + const char *filename) + { + struct dirfile *df; + struct dirent *d; ++ struct directory_contents *dc = dir->contents; + #ifdef WINDOWS32 + struct stat st; + int rehash = 0; + #endif + +- if (dir == 0 || dir->dirfiles.ht_vec == 0) ++ if (dc == 0 || dc->dirfiles.ht_vec == 0) + /* The directory could not be stat'd or opened. */ + return 0; + +@@ -671,7 +672,7 @@ dir_contents_file_exists_p (struct directory_contents *dir, + } + dirfile_key.name = filename; + dirfile_key.length = strlen (filename); +- df = hash_find_item (&dir->dirfiles, &dirfile_key); ++ df = hash_find_item (&dc->dirfiles, &dirfile_key); + if (df) + return !df->impossible; + } +@@ -679,7 +680,7 @@ dir_contents_file_exists_p (struct directory_contents *dir, + /* The file was not found in the hashed list. + Try to read the directory further. */ + +- if (dir->dirstream == 0) ++ if (dc->dirstream == 0) + { + #ifdef WINDOWS32 + /* +@@ -687,17 +688,17 @@ dir_contents_file_exists_p (struct directory_contents *dir, + * filesystems force a rehash always as mtime does not change + * on directories (ugh!). + */ +- if (dir->path_key) ++ if (dc->path_key) + { +- if ((dir->fs_flags & FS_FAT) != 0) ++ if ((dc->fs_flags & FS_FAT) != 0) + { +- dir->mtime = time ((time_t *) 0); ++ dc->mtime = time ((time_t *) 0); + rehash = 1; + } +- else if (stat (dir->path_key, &st) == 0 && st.st_mtime > dir->mtime) ++ else if (stat (dc->path_key, &st) == 0 && st.st_mtime > dc->mtime) + { + /* reset date stamp to show most recent re-process. */ +- dir->mtime = st.st_mtime; ++ dc->mtime = st.st_mtime; + rehash = 1; + } + +@@ -706,8 +707,8 @@ dir_contents_file_exists_p (struct directory_contents *dir, + return 0; + + /* make sure directory can still be opened; if not return. */ +- dir->dirstream = opendir (dir->path_key); +- if (!dir->dirstream) ++ dc->dirstream = opendir (dc->path_key); ++ if (!dc->dirstream) + return 0; + } + else +@@ -723,11 +724,11 @@ dir_contents_file_exists_p (struct directory_contents *dir, + struct dirfile dirfile_key; + struct dirfile **dirfile_slot; + +- ENULLLOOP (d, readdir (dir->dirstream)); ++ ENULLLOOP (d, readdir (dc->dirstream)); + if (d == 0) + { + if (errno) +- pfatal_with_name ("INTERNAL: readdir"); ++ OSS (fatal, NILF, "readdir %s: %s", dir->name, strerror (errno)); + break; + } + +@@ -747,7 +748,7 @@ dir_contents_file_exists_p (struct directory_contents *dir, + len = NAMLEN (d); + dirfile_key.name = d->d_name; + dirfile_key.length = len; +- dirfile_slot = (struct dirfile **) hash_find_slot (&dir->dirfiles, &dirfile_key); ++ dirfile_slot = (struct dirfile **) hash_find_slot (&dc->dirfiles, &dirfile_key); + #ifdef WINDOWS32 + /* + * If re-reading a directory, don't cache files that have +@@ -768,7 +769,7 @@ dir_contents_file_exists_p (struct directory_contents *dir, + #endif + df->length = len; + df->impossible = 0; +- hash_insert_at (&dir->dirfiles, df, dirfile_slot); ++ hash_insert_at (&dc->dirfiles, df, dirfile_slot); + } + /* Check if the name matches the one we're searching for. */ + if (filename != 0 && patheq (d->d_name, filename)) +@@ -777,12 +778,13 @@ dir_contents_file_exists_p (struct directory_contents *dir, + + /* If the directory has been completely read in, + close the stream and reset the pointer to nil. */ +- if (d == 0) ++ if (d == NULL) + { + --open_directories; +- closedir (dir->dirstream); +- dir->dirstream = 0; ++ closedir (dc->dirstream); ++ dc->dirstream = NULL; + } ++ + return 0; + } + +@@ -794,15 +796,10 @@ int + dir_file_exists_p (const char *dirname, const char *filename) + { + #ifdef VMS +- if ((filename != NULL) && (dirname != NULL)) +- { +- int want_vmsify; +- want_vmsify = (strpbrk (dirname, ":<[") != NULL); +- if (want_vmsify) +- filename = vmsify (filename, 0); +- } ++ if (filename && dirname && strpbrk (dirname, ":<[") != NULL) ++ filename = vmsify (filename, 0); + #endif +- return dir_contents_file_exists_p (find_directory (dirname)->contents, ++ return dir_contents_file_exists_p (find_directory (dirname), + filename); + } + +@@ -1225,7 +1222,7 @@ open_dirstream (const char *directory) + /* Read all the contents of the directory now. There is no benefit + in being lazy, since glob will want to see every file anyway. */ + +- dir_contents_file_exists_p (dir->contents, 0); ++ dir_contents_file_exists_p (dir, 0); + + new = xmalloc (sizeof (struct dirstream)); + new->contents = dir->contents; +diff --git a/src/function.c b/src/function.c +index f0ef3434..e4a3af86 100644 +--- a/src/function.c ++++ b/src/function.c +@@ -2801,7 +2801,7 @@ define_new_function (const floc *flocp, const char *name, + _("Invalid maximum argument count (%u) for function %s"), max, name); + + ent = xmalloc (sizeof (struct function_table_entry)); +- ent->name = name; ++ ent->name = strcache_add (name); + ent->len = (unsigned char) len; + ent->minimum_args = (unsigned char) min; + ent->maximum_args = (unsigned char) max; +diff --git a/src/hash.c b/src/hash.c +index 5d7ea81b..d1652f84 100644 +--- a/src/hash.c ++++ b/src/hash.c +@@ -361,7 +361,7 @@ round_up_2 (unsigned long n) + #define sum_get_unaligned_32(r, p) \ + do { \ + unsigned int val; \ +- memcpy(&val, (p), 4); \ ++ memcpy (&val, (p), 4); \ + r += val; \ + } while(0); + +@@ -413,13 +413,16 @@ jhash(unsigned const char *k, int length) + #define UINTSZ sizeof (unsigned int) + + #ifdef WORDS_BIGENDIAN +-/* The ifs are ordered from the first byte in memory to the last. */ ++/* The ifs are ordered from the first byte in memory to the last. ++ Help the compiler optimize by using static memcpy length. */ + #define sum_up_to_nul(r, p, plen, flag) \ + do { \ + unsigned int val = 0; \ + size_t pn = (plen); \ +- size_t n = pn < UINTSZ ? pn : UINTSZ; \ +- memcpy (&val, (p), n); \ ++ if (pn >= UINTSZ) \ ++ memcpy (&val, (p), UINTSZ); \ ++ else \ ++ memcpy (&val, (p), pn); \ + if ((val & 0xFF000000) == 0) \ + flag = 1; \ + else if ((val & 0xFF0000) == 0) \ +@@ -432,13 +435,16 @@ jhash(unsigned const char *k, int length) + #else + /* First detect the presence of zeroes. If there is none, we can + sum the 4 bytes directly. Otherwise, the ifs are ordered as in the +- big endian case, from the first byte in memory to the last. */ ++ big endian case, from the first byte in memory to the last. ++ Help the compiler optimize by using static memcpy length. */ + #define sum_up_to_nul(r, p, plen, flag) \ + do { \ + unsigned int val = 0; \ + size_t pn = (plen); \ +- size_t n = pn < UINTSZ ? pn : UINTSZ; \ +- memcpy (&val, (p), n); \ ++ if (pn >= UINTSZ) \ ++ memcpy (&val, (p), UINTSZ); \ ++ else \ ++ memcpy (&val, (p), pn); \ + flag = ((val - 0x01010101) & ~val) & 0x80808080; \ + if (!flag) \ + r += val; \ +diff --git a/src/main.c b/src/main.c +index eec93656..b31ddd4d 100644 +--- a/src/main.c ++++ b/src/main.c +@@ -1182,11 +1182,6 @@ main (int argc, char **argv, char **envp) + /* Useful for attaching debuggers, etc. */ + SPIN ("main-entry"); + +- /* Don't die if our stdout sends us SIGPIPE. */ +-#ifdef SIGPIPE +- bsd_signal (SIGPIPE, SIG_IGN); +-#endif +- + #ifdef HAVE_ATEXIT + if (ANY_SET (check_io_state (), IO_STDOUT_OK)) + atexit (close_stdout); +@@ -1264,6 +1259,9 @@ main (int argc, char **argv, char **envp) + #endif + #ifdef SIGQUIT + FATAL_SIG (SIGQUIT); ++#endif ++#ifdef SIGPIPE ++ FATAL_SIG (SIGPIPE); + #endif + FATAL_SIG (SIGINT); + FATAL_SIG (SIGTERM); +@@ -1505,7 +1503,7 @@ main (int argc, char **argv, char **envp) + + /* If this is MAKE_RESTARTS, check to see if the "already printed + the enter statement" flag is set. */ +- if (len == 13 && memcmp (envp[i], STRING_SIZE_TUPLE ("MAKE_RESTARTS")) == 0) ++ if (len == 13 && memcmp (envp[i], "MAKE_RESTARTS", CSTRLEN ("MAKE_RESTARTS")) == 0) + { + if (*ep == '-') + { +@@ -1930,6 +1928,9 @@ main (int argc, char **argv, char **envp) + _("Makefile from standard input specified twice")); + + outfile = get_tmpfile (&newnm); ++ if (!outfile) ++ O (fatal, NILF, ++ _("cannot store makefile from stdin to a temporary file")); + + while (!feof (stdin) && ! ferror (stdin)) + { +diff --git a/src/misc.c b/src/misc.c +index 8264fe9f..00dce749 100644 +--- a/src/misc.c ++++ b/src/misc.c +@@ -20,8 +20,7 @@ this program. If not, see <https://www.gnu.org/licenses/>. */ + #include "os.h" + #include "debug.h" + +-/* GNU make no longer supports pre-ANSI89 environments. */ +- ++#include <assert.h> + #include <stdarg.h> + + #ifdef WINDOWS32 +@@ -650,11 +649,19 @@ get_tmppath () + # ifdef HAVE_MKTEMP + path = get_tmptemplate (); + if (*mktemp (path) == '\0') +- pfatal_with_name ("mktemp"); ++ { ++ OSS (error, NILF, ++ _("cannot generate temp path from %s: %s"), path, strerror (errno)); ++ return NULL; ++ } + # else + path = xmalloc (L_tmpnam + 1); + if (tmpnam (path) == NULL) +- pfatal_with_name ("tmpnam"); ++ { ++ OS (error, NILF, ++ _("cannot generate temp name: %s"), strerror (errno)); ++ return NULL; ++ } + # endif + + return path; +@@ -662,7 +669,9 @@ get_tmppath () + #endif + + /* Generate a temporary file and return an fd for it. If name is NULL then +- the temp file is anonymous and will be deleted when the process exits. */ ++ the temp file is anonymous and will be deleted when the process exits. If ++ name is not null then *name will point to an allocated buffer, or set to ++ NULL on failure. */ + int + get_tmpfd (char **name) + { +@@ -670,9 +679,11 @@ get_tmpfd (char **name) + char *tmpnm; + mode_t mask; + +- /* If there's an os-specific way to get an anoymous temp file use it. */ +- if (!name) ++ if (name) ++ *name = NULL; ++ else + { ++ /* If there's an os-specific way to get an anoymous temp file use it. */ + fd = os_anontmp (); + if (fd >= 0) + return fd; +@@ -689,13 +700,19 @@ get_tmpfd (char **name) + EINTRLOOP (fd, mkstemp (tmpnm)); + #else + tmpnm = get_tmppath (); ++ if (!tmpnm) ++ return -1; + + /* Can't use mkstemp(), but try to guard against a race condition. */ + EINTRLOOP (fd, open (tmpnm, O_CREAT|O_EXCL|O_RDWR, 0600)); + #endif + if (fd < 0) +- OSS (fatal, NILF, +- _("create temporary file %s: %s"), tmpnm, strerror (errno)); ++ { ++ OSS (error, NILF, ++ _("cannot create temporary file %s: %s"), tmpnm, strerror (errno)); ++ free (tmpnm); ++ return -1; ++ } + + if (name) + *name = tmpnm; +@@ -704,8 +721,8 @@ get_tmpfd (char **name) + int r; + EINTRLOOP (r, unlink (tmpnm)); + if (r < 0) +- OSS (fatal, NILF, +- _("unlink temporary file %s: %s"), tmpnm, strerror (errno)); ++ OSS (error, NILF, ++ _("cannot unlink temporary file %s: %s"), tmpnm, strerror (errno)); + free (tmpnm); + } + +@@ -715,8 +732,8 @@ get_tmpfd (char **name) + } + + /* Return a FILE* for a temporary file, opened in the safest way possible. +- Set name to point to an allocated buffer containing the name of the file. +- Note, this cannot be NULL! */ ++ Set name to point to an allocated buffer containing the name of the file, ++ or NULL on failure. Note, name cannot be NULL! */ + FILE * + get_tmpfile (char **name) + { +@@ -725,26 +742,37 @@ get_tmpfile (char **name) + FILE *file; + + #if defined(HAVE_FDOPEN) +- int fd = get_tmpfd (name); ++ int fd; ++ assert (name); ++ fd = get_tmpfd (name); ++ if (fd < 0) ++ return NULL; ++ assert (*name); + + ENULLLOOP (file, fdopen (fd, tmpfile_mode)); + if (file == NULL) +- OSS (fatal, NILF, ++ OSS (error, NILF, + _("fdopen: temporary file %s: %s"), *name, strerror (errno)); + #else + /* Preserve the current umask, and set a restrictive one for temp files. */ + mode_t mask = umask (0077); +- int err; + ++ assert (name); + *name = get_tmppath (); ++ if (!*name) ++ return NULL; + + /* Although this fopen is insecure, it is executed only on non-fdopen + platforms, which should be a rarity nowadays. */ + + ENULLLOOP (file, fopen (*name, tmpfile_mode)); + if (file == NULL) +- OSS (fatal, NILF, +- _("fopen: temporary file %s: %s"), *name, strerror (errno)); ++ { ++ OSS (error, NILF, ++ _("fopen: temporary file %s: %s"), *name, strerror (errno)); ++ free (*name); ++ *name = NULL; ++ } + + umask (mask); + #endif +diff --git a/src/output.c b/src/output.c +index 43eb2f06..22387dff 100644 +--- a/src/output.c ++++ b/src/output.c +@@ -248,6 +248,9 @@ setup_tmpfile (struct output *out) + + /* If we failed to create a temp file, disable output sync going forward. */ + error: ++ O (error, NILF, ++ _("cannot open output-sync lock file, suppressing output-sync.")); ++ + output_close (out); + output_sync = OUTPUT_SYNC_NONE; + osync_clear (); +diff --git a/src/posixos.c b/src/posixos.c +index 44aeb346..78358dd8 100644 +--- a/src/posixos.c ++++ b/src/posixos.c +@@ -167,12 +167,12 @@ jobserver_setup (int slots, const char *style) + hang until the write side is open. */ + EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY|O_NONBLOCK)); + if (job_fds[0] < 0) +- OSS (fatal, NILF, _("Cannot open jobserver %s: %s"), ++ OSS (fatal, NILF, _("cannot open jobserver %s: %s"), + fifo_name, strerror (errno)); + + EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY)); + if (job_fds[0] < 0) +- OSS (fatal, NILF, _("Cannot open jobserver %s: %s"), ++ OSS (fatal, NILF, _("cannot open jobserver %s: %s"), + fifo_name, strerror (errno)); + + js_type = js_fifo; +@@ -183,7 +183,7 @@ jobserver_setup (int slots, const char *style) + if (js_type == js_none) + { + if (style && strcmp (style, "pipe") != 0) +- OS (fatal, NILF, _("Unknown jobserver auth style '%s'"), style); ++ OS (fatal, NILF, _("unknown jobserver auth style '%s'"), style); + + EINTRLOOP (r, pipe (job_fds)); + if (r < 0) +@@ -229,14 +229,19 @@ jobserver_parse_auth (const char *auth) + + EINTRLOOP (job_fds[0], open (fifo_name, O_RDONLY)); + if (job_fds[0] < 0) +- OSS (fatal, NILF, +- _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno)); ++ { ++ OSS (error, NILF, ++ _("cannot open jobserver %s: %s"), fifo_name, strerror (errno)); ++ return 0; ++ } + + EINTRLOOP (job_fds[1], open (fifo_name, O_WRONLY)); +- if (job_fds[0] < 0) +- OSS (fatal, NILF, +- _("Cannot open jobserver %s: %s"), fifo_name, strerror (errno)); +- ++ if (job_fds[1] < 0) ++ { ++ OSS (error, NILF, ++ _("cannot open jobserver %s: %s"), fifo_name, strerror (errno)); ++ return 0; ++ } + js_type = js_fifo; + } + /* If not, it must be a simple pipe. */ +@@ -867,12 +872,15 @@ os_anontmp () + FILE *tfile; + ENULLLOOP (tfile, tmpfile ()); + if (!tfile) +- pfatal_with_name ("tmpfile"); ++ { ++ OS (error, NILF, "tmpfile: %s", strerror (errno)); ++ return -1; ++ } + umask (mask); + + EINTRLOOP (fd, dup (fileno (tfile))); + if (fd < 0) +- pfatal_with_name ("dup"); ++ OS (error, NILF, "dup: %s", strerror (errno)); + fclose (tfile); + } + #endif +diff --git a/src/read.c b/src/read.c +index 07431240..15f58ecf 100644 +--- a/src/read.c ++++ b/src/read.c +@@ -1140,20 +1140,29 @@ eval (struct ebuffer *ebuf, int set_default) + + p2 = next_token (variable_buffer); + +- /* If the word we're looking at is EOL, see if there's _anything_ +- on the line. If not, a variable expanded to nothing, so ignore +- it. If so, we can't parse this line so punt. */ ++ /* If we're at EOL we didn't find a separator so we don't know what ++ kind of line this is. */ + if (wtype == w_eol) + { ++ /* Ignore an empty line. */ + if (*p2 == '\0') + continue; + +- /* There's no need to be ivory-tower about this: check for +- one of the most common bugs found in makefiles... */ ++ /* Check for spaces instead of TAB. */ + if (cmd_prefix == '\t' && strneq (line, " ", 8)) + O (fatal, fstart, _("missing separator (did you mean TAB instead of 8 spaces?)")); +- else +- O (fatal, fstart, _("missing separator")); ++ ++ /* Check for conditionals without whitespace afterward. ++ We don't check ifdef/ifndef because there's no real way to miss ++ whitespace there. */ ++ p2 = next_token (line); ++ if (strneq (p2, "if", 2) && ++ ((strneq (&p2[2], "neq", 3) && !STOP_SET (p2[5], MAP_BLANK)) ++ || (strneq (&p2[2], "eq", 2) && !STOP_SET (p2[4], MAP_BLANK)))) ++ O (fatal, fstart, _("missing separator (ifeq/ifneq must be followed by whitespace)")); ++ ++ /* No idea... */ ++ O (fatal, fstart, _("missing separator")); + } + + { +diff --git a/src/w32/w32os.c b/src/w32/w32os.c +index 9c5dec24..213bbf12 100644 +--- a/src/w32/w32os.c ++++ b/src/w32/w32os.c +@@ -216,12 +216,12 @@ jobserver_setup (int slots, const char *style) + /* sub_proc.c is limited in the number of objects it can wait for. */ + + if (style && strcmp (style, "sem") != 0) +- OS (fatal, NILF, _("Unknown jobserver auth style '%s'"), style); ++ OS (fatal, NILF, _("unknown jobserver auth style '%s'"), style); + + if (slots > process_table_usable_size()) + { + slots = process_table_usable_size(); +- DB (DB_JOBS, (_("Jobserver slots limited to %d\n"), slots)); ++ DB (DB_JOBS, (_("jobserver slots limited to %d\n"), slots)); + } + + sprintf (jobserver_semaphore_name, "gmake_semaphore_%d", _getpid ()); +@@ -255,10 +255,12 @@ jobserver_parse_auth (const char *auth) + { + DWORD err = GetLastError (); + const char *estr = map_windows32_error_to_string (err); +- fatal (NILF, strlen (auth) + INTSTR_LENGTH + strlen (estr), +- _("internal error: unable to open jobserver semaphore '%s': (Error %ld: %s)"), ++ error (NILF, strlen (auth) + INTSTR_LENGTH + strlen (estr), ++ _("unable to open jobserver semaphore '%s': (Error %ld: %s)"), + auth, err, estr); ++ return 0; + } ++ + DB (DB_JOBS, (_("Jobserver client (semaphore %s)\n"), auth)); + + return 1; +diff --git a/tests/run_make_tests.pl b/tests/run_make_tests.pl +index 70dd1821..5fc37595 100644 +--- a/tests/run_make_tests.pl ++++ b/tests/run_make_tests.pl +@@ -185,7 +185,6 @@ sub subst_make_string + s/#PERL#/$perl_name/g; + s/#PWD#/$cwdpath/g; + s/#WORK#/$workdir/g; +- # If we're using a shell + s/#HELPER#/$perl_name $helptool/g; + return $_; + } +diff --git a/tests/scripts/features/jobserver b/tests/scripts/features/jobserver +index 8ecbe345..e12facf0 100644 +--- a/tests/scripts/features/jobserver ++++ b/tests/scripts/features/jobserver +@@ -14,6 +14,7 @@ if (!$parallel_jobs) { + + # Shorthand + my $np = '--no-print-directory'; ++my $j1err = "warning: jobserver unavailable: using -j1. Add '+' to parent make rule."; + + # Simple test of MAKEFLAGS settings + run_make_test(q! +@@ -90,7 +91,7 @@ if ($port_type ne 'W32') { + default: ; @ #MAKEPATH# -f Makefile2 + !, + "--jobserver-style=pipe -j2 $np", +-"#MAKE#[1]: warning: jobserver unavailable: using -j1. Add '+' to parent make rule. ++"#MAKE#[1]: $j1err + #MAKE#[1]: Nothing to be done for 'foo'."); + + rmfiles('Makefile2'); +@@ -98,15 +99,15 @@ default: ; @ #MAKEPATH# -f Makefile2 + + # For Windows and named pipes, we don't need to worry about recursion + if ($port_type eq 'W32' || exists $FEATURES{'jobserver-fifo'}) { +- create_file('Makefile2', "vpath %.c ../\n", "foo:\n"); ++ create_file('Makefile2', "vpath %.c ../\n", "foo:\n"); + +- run_make_test(q! ++ run_make_test(q! + default: ; @ #MAKEPATH# -f Makefile2 + !, + "-j2 $np", + "#MAKE#[1]: Nothing to be done for 'foo'."); + +- rmfiles('Makefile2'); ++ rmfiles('Makefile2'); + } + + # Ensure enter/leave directory messages appear before jobserver warnings +@@ -129,17 +130,17 @@ all: a + all a: ; @echo $@ + !, + '--jobserver-style=foo -j8', +- "#MAKE#: *** Unknown jobserver auth style 'foo'. Stop.", 512); +- +-# sv 62908. +-# Test that when mkfifo fails, make switches to pipe and succeeds. +-# Force mkfifo to fail by attempting to create a fifo in a non existent +-# directory. +-# run_make_test does not allow matching a multiline pattern, therefore run the +-# test twice. +-# First time look for /$ERR_no_such_file/ to ensure mkfifo failed. +-# Second time look for /Nothing to be done/ to ensure make succeeded. ++ "#MAKE#: *** unknown jobserver auth style 'foo'. Stop.", 512); ++ + if (exists $FEATURES{'jobserver-fifo'}) { ++ # sv 62908. ++ # Test that when mkfifo fails, make switches to pipe and succeeds. ++ # Force mkfifo to fail by attempting to create a fifo in a non existent ++ # directory. ++ # run_make_test does not allow matching a multiline pattern, therefore run ++ # the test twice. ++ # First time look for /$ERR_no_such_file/ to ensure mkfifo failed. ++ # Second time look for /Nothing to be done/ to ensure make succeeded. + $ENV{TMPDIR} = "nosuchdir"; + run_make_test("all:\n", '-j2', "/$ERR_no_such_file/"); + +@@ -155,6 +156,10 @@ recurse: ; @$(MAKE) -f #MAKEFILE# all + all:;@echo "$$MAKEFLAGS" + !, + "-j2 --no-print-directory", "/--jobserver-auth=fifo:\\./"); ++ ++ # Verify we fall back to -j1 but continue, of the auth is bad. ++ $ENV{MAKEFLAGS} = '-j2 --jobserver-auth=fifo:nosuchfile'; ++ run_make_test(q!all:;@echo hi!, "", "#MAKE#: cannot open jobserver nosuchfile: $ERR_no_such_file\n#MAKE#: $j1err\nhi\n"); + } + + 1; +diff --git a/tests/scripts/features/output-sync b/tests/scripts/features/output-sync +index 13a54ca0..18c85c0a 100644 +--- a/tests/scripts/features/output-sync ++++ b/tests/scripts/features/output-sync +@@ -360,11 +360,27 @@ use POSIX (); + # file. + run_make_test(q! + pid:=$(shell echo $$PPID) +-all:; @kill -TERM $(pid) && sleep 16 ++all:; @#HELPER# term $(pid) sleep 10 + !, '-O -j2', '/#MAKE#: \*\*\* \[#MAKEFILE#:3: all] Terminated/', POSIX::SIGTERM); + } +- + unlink($fout); ++ ++# SV 63333. Test that make continues to run without output sync when we ++# cannot create a temporary file. ++# Create a non-writable temporary directory. ++# Run the test twice, because run_make_test cannot match a regex againt a ++# multiline input. ++my $tdir = 'test_tmp_dir'; ++mkdir($tdir, 0500); ++$ENV{'TMPDIR'} = $tdir; ++ ++run_make_test(q! ++all:; $(info hello, world) ++!, '-Orecurse', "/suppressing output-sync/"); ++ ++run_make_test(undef, '-Orecurse', "/#MAKE#: 'all' is up to date./"); ++ ++rmdir($tdir); + } + + # This tells the test driver that the perl test script executed properly. +diff --git a/tests/scripts/features/temp_stdin b/tests/scripts/features/temp_stdin +index b06df53e..3bd53e02 100644 +--- a/tests/scripts/features/temp_stdin ++++ b/tests/scripts/features/temp_stdin +@@ -71,7 +71,7 @@ run_make_test(q! + include bye.mk + pid:=$(shell echo $$PPID) + all:; +-bye.mk: force; @kill -TERM $(pid) && sleep 16 ++bye.mk: force; @#HELPER# term $(pid) sleep 10 + force: + !, '-f-', '/#MAKE#: \*\*\* \[#MAKEFILE#:5: bye.mk] Terminated/', POSIX::SIGTERM); + } +@@ -109,6 +109,21 @@ force: + @make_command = @make_orig; + unlink($makecopy); + rmdir($tmakedir); ++ ++# SV 63333. Test that make exits with an error message if we cannot store a ++# makefile from stdin to a temporary file. ++# Create a non-writable temporary directory. ++ ++my $tdir = 'test_tmp_dir'; ++mkdir($tdir, 0500); ++$ENV{'TMPDIR'} = $tdir; ++close(STDIN); ++open(STDIN, "<", 'input.mk') || die "$0: cannot open input.mk for reading: $!"; ++ ++run_make_test(q! ++all:; $(info hello, world) ++!, '-f-', '/cannot store makefile from stdin to a temporary file. Stop./', 512); ++rmdir($tdir); + } + + close(STDIN); +diff --git a/tests/scripts/misc/failure b/tests/scripts/misc/failure +new file mode 100644 +index 00000000..edd90fbb +--- /dev/null ++++ b/tests/scripts/misc/failure +@@ -0,0 +1,49 @@ ++# -*-perl-*- ++ ++$description = "Test miscellaneous failures."; ++ ++ ++# Test that the "did you mean TAB" message is printed properly ++ ++run_make_test(q! ++$x. ++!, ++ '', '#MAKEFILE#:2: *** missing separator. Stop.', 512); ++ ++run_make_test(q! ++foo: ++ bar ++!, ++ '', '#MAKEFILE#:3: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.', 512); ++ ++run_make_test(q! ++.RECIPEPREFIX = : ++foo: ++ bar ++!, ++ '', '#MAKEFILE#:4: *** missing separator. Stop.', 512); ++ ++for my $kw ('eq', 'neq') { ++run_make_test(qq! ++if$kw(foo,bar) ++\$(error ouch) ++endif ++!, ++ '', '#MAKEFILE#:2: *** missing separator (ifeq/ifneq must be followed by whitespace). Stop.', 512); ++ ++run_make_test(qq! ++if$kw ++\$(error ouch) ++endif ++!, ++ '', '#MAKEFILE#:2: *** invalid syntax in conditional. Stop.', 512); ++ ++run_make_test(qq! ++if$kw blah ++\$(error ouch) ++endif ++!, ++ '', '#MAKEFILE#:2: *** invalid syntax in conditional. Stop.', 512); ++} ++ ++1; +diff --git a/tests/scripts/variables/special b/tests/scripts/variables/special +index 68f3128c..abe9fc0c 100644 +--- a/tests/scripts/variables/special ++++ b/tests/scripts/variables/special +@@ -122,26 +122,6 @@ reset-four \ + : foo-three + : foo-four'); + +-# Test that the "did you mean TAB" message is printed properly +- +-run_make_test(q! +-$x. +-!, +- '', '#MAKEFILE#:2: *** missing separator. Stop.', 512); +- +-run_make_test(q! +-foo: +- bar +-!, +- '', '#MAKEFILE#:3: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.', 512); +- +-run_make_test(q! +-.RECIPEPREFIX = : +-foo: +- bar +-!, +- '', '#MAKEFILE#:4: *** missing separator. Stop.', 512); +- + 1; + + ### Local Variables: +diff --git a/tests/test_driver.pl b/tests/test_driver.pl +index b64fffb6..efe4981d 100644 +--- a/tests/test_driver.pl ++++ b/tests/test_driver.pl +@@ -806,12 +806,135 @@ sub error + die "$caller: $message"; + } + ++sub compare_answer_vms ++{ ++ my ($kgo, $log) = @_; ++ ++ # VMS has extra blank lines in output sometimes. ++ # Ticket #41760 ++ $log =~ s/\n\n+/\n/gm; ++ $log =~ s/\A\n+//g; ++ return 1 if ($kgo eq $log); ++ ++ # VMS adding a "Waiting for unfinished jobs..." ++ # Remove it for now to see what else is going on. ++ $log =~ s/^.+\*\*\* Waiting for unfinished jobs.+$//m; ++ $log =~ s/\n\n/\n/gm; ++ $log =~ s/^\n+//gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS wants target device to exist or generates an error, ++ # Some test tagets look like VMS devices and trip this. ++ $log =~ s/^.+\: no such device or address.*$//gim; ++ $log =~ s/\n\n/\n/gm; ++ $log =~ s/^\n+//gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS error message has a different case ++ $log =~ s/no such file /No such file /gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS is putting comas instead of spaces in output ++ $log =~ s/,/ /gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS Is sometimes adding extra leading spaces to output? ++ { ++ (my $mlog = $log) =~ s/^ +//gm; ++ return 1 if ($mlog eq $kgo); ++ } ++ ++ # VMS port not handling POSIX encoded child status ++ # Translate error case it for now. ++ $log =~ s/0x1035a00a/1/gim; ++ return 1 if ($log =~ /\Q$kgo\E/i); ++ ++ $log =~ s/0x1035a012/2/gim; ++ return 1 if ($log eq $kgo); ++ ++ # Tests are using a UNIX null command, temp hack ++ # until this can be handled by the VMS port. ++ # ticket # 41761 ++ $log =~ s/^.+DCL-W-NOCOMD.*$//gim; ++ $log =~ s/\n\n+/\n/gm; ++ $log =~ s/^\n+//gm; ++ return 1 if ($log eq $kgo); ++ ++ # Tests are using exit 0; ++ # this generates a warning that should stop the make, but does not ++ $log =~ s/^.+NONAME-W-NOMSG.*$//gim; ++ $log =~ s/\n\n+/\n/gm; ++ $log =~ s/^\n+//gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS is sometimes adding single quotes to output? ++ $log =~ s/\'//gm; ++ return 1 if ($log eq $kgo); ++ ++ # And missing an extra space in output ++ $kgo =~ s/\h\h+/ /gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS adding ; to end of some lines. ++ $log =~ s/;\n/\n/gm; ++ return 1 if ($log eq $kgo); ++ ++ # VMS adding trailing space to end of some quoted lines. ++ $log =~ s/\h+\n/\n/gm; ++ return 1 if ($log eq $kgo); ++ ++ # And VMS missing leading blank line ++ $kgo =~ s/\A\n//g; ++ return 1 if ($log eq $kgo); ++ ++ # Unix double quotes showing up as single quotes on VMS. ++ $kgo =~ s/\"//g; ++ return 1 if ($log eq $kgo); ++ ++ return 0; ++} ++ ++sub compare_answer ++{ ++ my ($kgo, $log) = @_; ++ my ($mkgo, $mlog); ++ ++ # For make, get rid of any time skew error before comparing--too bad this ++ # has to go into the "generic" driver code :-/ ++ $log =~ s/^.*modification time .*in the future.*\n//gm; ++ $log =~ s/^.*Clock skew detected.*\n//gm; ++ return 1 if ($log eq $kgo); ++ ++ # Get rid of newline differences, forever ++ $kgo =~ s,\r\n,\n,gs; ++ $log =~ s,\r\n,\n,gs; ++ return 1 if ($log eq $kgo); ++ ++ # See if it is a backslash problem (only on W32?) ++ ($mkgo = $kgo) =~ tr,\\,/,; ++ ($mlog = $log) =~ tr,\\,/,; ++ return 1 if ($log eq $kgo); ++ ++ # VMS is a whole thing... ++ return 1 if ($^O eq 'VMS' && compare_answer_vms($mkgo, $mlog)); ++ ++ # See if the answer might be a regex. ++ if ($kgo =~ m,^/(.+)/$,) { ++ return 1 if ($log =~ /$1/); ++ ++ # We can't test with backslashes converted to forward slashes, because ++ # backslashes could be escaping RE special characters! ++ } ++ ++ return 0; ++} ++ + my %old_tempfiles = (); + + sub compare_output + { + my ($answer, $logfile) = @_; +- my ($slurp, $answer_matched, $extra) = ('', 0, 0); ++ my ($slurp, $matched, $extra) = ('', 0, 0); + + ++$tests_run; + +@@ -831,169 +954,25 @@ sub compare_output + + if (! defined $answer) { + print "Ignoring output ........ " if $debug; +- $answer_matched = 1; ++ $matched = 1; + } else { + print "Comparing output ........ " if $debug; + +- $slurp = &read_file_into_string ($logfile); +- +- # For make, get rid of any time skew error before comparing--too bad this +- # has to go into the "generic" driver code :-/ +- $slurp =~ s/^.*modification time .*in the future.*\n//gm; +- $slurp =~ s/^.*Clock skew detected.*\n//gm; +- +- if ($slurp eq $answer) { +- $answer_matched = 1; +- } else { +- # See if it is a slash or CRLF problem +- my ($answer_mod, $slurp_mod) = ($answer, $slurp); +- +- $answer_mod =~ tr,\\,/,; +- $answer_mod =~ s,\r\n,\n,gs; +- +- $slurp_mod =~ tr,\\,/,; +- $slurp_mod =~ s,\r\n,\n,gs; +- +- $answer_matched = ($slurp_mod eq $answer_mod); +- +- if (!$answer_matched && $^O eq 'VMS') { +- +- # VMS has extra blank lines in output sometimes. +- # Ticket #41760 +- if (!$answer_matched) { +- $slurp_mod =~ s/\n\n+/\n/gm; +- $slurp_mod =~ s/\A\n+//g; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS adding a "Waiting for unfinished jobs..." +- # Remove it for now to see what else is going on. +- if (!$answer_matched) { +- $slurp_mod =~ s/^.+\*\*\* Waiting for unfinished jobs.+$//m; +- $slurp_mod =~ s/\n\n/\n/gm; +- $slurp_mod =~ s/^\n+//gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS wants target device to exist or generates an error, +- # Some test tagets look like VMS devices and trip this. +- if (!$answer_matched) { +- $slurp_mod =~ s/^.+\: no such device or address.*$//gim; +- $slurp_mod =~ s/\n\n/\n/gm; +- $slurp_mod =~ s/^\n+//gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS error message has a different case +- if (!$answer_matched) { +- $slurp_mod =~ s/no such file /No such file /gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS is putting comas instead of spaces in output +- if (!$answer_matched) { +- $slurp_mod =~ s/,/ /gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS Is sometimes adding extra leading spaces to output? +- if (!$answer_matched) { +- my $slurp_mod = $slurp_mod; +- $slurp_mod =~ s/^ +//gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS port not handling POSIX encoded child status +- # Translate error case it for now. +- if (!$answer_matched) { +- $slurp_mod =~ s/0x1035a00a/1/gim; +- $answer_matched = 1 if $slurp_mod =~ /\Q$answer_mod\E/i; +- +- } +- if (!$answer_matched) { +- $slurp_mod =~ s/0x1035a012/2/gim; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # Tests are using a UNIX null command, temp hack +- # until this can be handled by the VMS port. +- # ticket # 41761 +- if (!$answer_matched) { +- $slurp_mod =~ s/^.+DCL-W-NOCOMD.*$//gim; +- $slurp_mod =~ s/\n\n+/\n/gm; +- $slurp_mod =~ s/^\n+//gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- # Tests are using exit 0; +- # this generates a warning that should stop the make, but does not +- if (!$answer_matched) { +- $slurp_mod =~ s/^.+NONAME-W-NOMSG.*$//gim; +- $slurp_mod =~ s/\n\n+/\n/gm; +- $slurp_mod =~ s/^\n+//gm; +- $answer_matched = ($slurp_mod eq $answer_mod); +- } +- +- # VMS is sometimes adding single quotes to output? +- if (!$answer_matched) { +- my $noq_slurp_mod = $slurp_mod; +- $noq_slurp_mod =~ s/\'//gm; +- $answer_matched = ($noq_slurp_mod eq $answer_mod); +- +- # And missing an extra space in output +- if (!$answer_matched) { +- $noq_answer_mod = $answer_mod; +- $noq_answer_mod =~ s/\h\h+/ /gm; +- $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); +- } +- +- # VMS adding ; to end of some lines. +- if (!$answer_matched) { +- $noq_slurp_mod =~ s/;\n/\n/gm; +- $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); +- } +- +- # VMS adding trailing space to end of some quoted lines. +- if (!$answer_matched) { +- $noq_slurp_mod =~ s/\h+\n/\n/gm; +- $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); +- } +- +- # And VMS missing leading blank line +- if (!$answer_matched) { +- $noq_answer_mod =~ s/\A\n//g; +- $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); +- } +- +- # Unix double quotes showing up as single quotes on VMS. +- if (!$answer_matched) { +- $noq_answer_mod =~ s/\"//g; +- $answer_matched = ($noq_slurp_mod eq $noq_answer_mod); +- } +- } +- } +- +- # If it still doesn't match, see if the answer might be a regex. +- if (!$answer_matched && $answer =~ m,^/(.+)/$,) { +- $answer_matched = ($slurp =~ /$1/); +- if (!$answer_matched && $answer_mod =~ m,^/(.+)/$,) { +- $answer_matched = ($slurp_mod =~ /$1/); +- } +- } +- } ++ $matched = compare_answer($answer, &read_file_into_string ($logfile)); + } + +- if ($keep || ! $answer_matched) { ++ if ($keep || ! $matched) { + &create_file(&get_basefile, $answer); + &create_file(&get_runfile, $command_string); + } + +- if ($answer_matched && $test_passed && !$extra) { ++ if ($matched && $test_passed && !$extra) { + print "ok\n" if $debug; + ++$tests_passed; + return 1; + } + +- if (! $answer_matched) { ++ if (! $matched) { + print "DIFFERENT OUTPUT\n" if $debug; + + print "\nCreating Difference File ...\n" if $debug; +@@ -1001,10 +980,11 @@ sub compare_output + # Create the difference file + my $base = get_basefile(); + if ($diff_name) { +- my $command = "$diff_name -c $base $logfile"; +- &run_command_with_output(get_difffile(), $command); ++ &run_command_with_output(get_difffile(), ++ "$diff_name -c $base $logfile"); + } else { +- create_file(get_difffile(), "Log file $logfile differs from base file $base\n"); ++ create_file(get_difffile(), ++ "Log file $logfile differs from base file $base\n"); + } + } + +diff --git a/tests/thelp.pl b/tests/thelp.pl +index 993339cb..c243bcb8 100755 +--- a/tests/thelp.pl ++++ b/tests/thelp.pl +@@ -16,6 +16,7 @@ + # wait <word> : wait for a file named <word> to exist + # tmout <secs> : Change the timeout for waiting. Default is 4 seconds. + # sleep <secs> : Sleep for <secs> seconds then echo <secs> ++# term <pid> : send SIGTERM to PID <pid> + # fail <err> : echo <err> to stdout then exit with error code err + # + # If given -q only the "out" command generates output. +@@ -95,6 +96,12 @@ sub op { + return 1; + } + ++ if ($op eq 'term') { ++ print "term $nm\n"; ++ kill('TERM', $nm); ++ return 1; ++ } ++ + if ($op eq 'fail') { + print "fail $nm\n"; + exit($nm);