[SV 40236] Handle included file open failures properly.

* read.c (eval_makefile): Set deps->error if we discovered any
error reading makefiles, and set NONEXISTENT_MTIME so we know
it needs to be rebuilt.
* main.c (main): Clean up management of makefile_mtimes.
* tests/scripts/features/include: Add open failure testcases.
This commit is contained in:
Paul Smith 2016-12-25 17:41:50 -05:00
parent 45bf0e3a67
commit c5ccc4930c
3 changed files with 52 additions and 45 deletions

27
main.c
View File

@ -2150,12 +2150,11 @@ main (int argc, char **argv, char **envp)
OUTPUT_UNSET ();
output_close (&make_sync);
if (read_files != 0)
if (read_files)
{
/* Update any makefiles if necessary. */
FILE_TIMESTAMP *makefile_mtimes = 0;
unsigned int mm_idx = 0;
FILE_TIMESTAMP *makefile_mtimes;
char **aargv = NULL;
const char **nargv;
int nargc;
@ -2163,12 +2162,22 @@ main (int argc, char **argv, char **envp)
DB (DB_BASIC, (_("Updating makefiles....\n")));
{
struct goaldep *d;
unsigned int num_mkfiles;
for (d = read_files; d != NULL; d = d->next)
++num_mkfiles;
makefile_mtimes = alloca (num_mkfiles * sizeof (FILE_TIMESTAMP));
}
/* Remove any makefiles we don't want to try to update. Record the
current modtimes of the others so we can compare them later. */
{
register struct goaldep *d, *last;
last = 0;
d = read_files;
struct goaldep *d = read_files;
struct goaldep *last = NULL;
unsigned int mm_idx = 0;
while (d != 0)
{
struct file *f;
@ -2202,9 +2211,6 @@ main (int argc, char **argv, char **envp)
}
else
{
makefile_mtimes = xrealloc (makefile_mtimes,
(mm_idx+1)
* sizeof (FILE_TIMESTAMP));
makefile_mtimes[mm_idx++] = file_mtime_no_search (d->file);
last = d;
d = d->next;
@ -2453,9 +2459,6 @@ main (int argc, char **argv, char **envp)
free (aargv);
break;
}
/* Free the makefile mtimes. */
free (makefile_mtimes);
}
/* Set up 'MAKEFLAGS' again for the normal targets. */

42
read.c
View File

@ -318,7 +318,11 @@ eval_makefile (const char *filename, int flags)
struct ebuffer ebuf;
const floc *curfile;
char *expanded = 0;
int makefile_errno;
/* Create a new goaldep entry. */
deps = alloc_goaldep ();
deps->next = read_files;
read_files = deps;
ebuf.floc.filenm = filename; /* Use the original file name. */
ebuf.floc.lineno = 1;
@ -349,13 +353,12 @@ eval_makefile (const char *filename, int flags)
filename = expanded;
}
errno = 0;
ENULLLOOP (ebuf.fp, fopen (filename, "r"));
/* Save the error code so we print the right message later. */
makefile_errno = errno;
deps->error = errno;
/* Check for unrecoverable errors: out of mem or FILE slots. */
switch (makefile_errno)
switch (deps->error)
{
#ifdef EMFILE
case EMFILE:
@ -365,7 +368,7 @@ eval_makefile (const char *filename, int flags)
#endif
case ENOMEM:
{
const char *err = strerror (makefile_errno);
const char *err = strerror (deps->error);
OS (fatal, reading_file, "%s", err);
}
}
@ -389,14 +392,8 @@ eval_makefile (const char *filename, int flags)
}
}
/* Now we have the final name for this makefile. Enter it into
the cache. */
/* Enter the final name for this makefile as a goaldep. */
filename = strcache_add (filename);
/* Add FILENAME to the chain of read makefiles. */
deps = alloc_goaldep ();
deps->next = read_files;
read_files = deps;
deps->file = lookup_file (filename);
if (deps->file == 0)
deps->file = enter_file (filename);
@ -405,17 +402,19 @@ eval_makefile (const char *filename, int flags)
free (expanded);
/* If the makefile can't be found at all, give up entirely. */
if (ebuf.fp == 0)
{
/* If we did some searching, errno has the error from the last
attempt, rather from FILENAME itself. Store it in case the
caller wants to use it in a message. */
errno = makefile_errno;
/* The makefile can't be read at all, give up entirely.
If we did some searching errno has the error from the last attempt,
rather from FILENAME itself: recover the more accurate one. */
errno = deps->error;
deps->file->last_mtime = NONEXISTENT_MTIME;
return deps;
}
/* Success; clear errno. */
deps->error = 0;
/* Set close-on-exec to avoid leaking the makefile to children, such as
$(shell ...). */
#ifdef HAVE_FILENO
@ -904,10 +903,7 @@ eval (struct ebuffer *ebuf, int set_default)
struct goaldep *d = eval_makefile (files->name, flags);
if (errno)
{
d->error = (unsigned short)errno;
d->floc = *fstart;
}
d->floc = *fstart;
free_ns (files);
files = next;

View File

@ -235,17 +235,25 @@ inc1: foo; echo > $@
rmfiles('inc1');
# include a directory
# Including files that can't be read should show an error
create_file('inc1', 'FOO := foo');
chmod 0000, 'inc1';
if ($all_tests) {
# Test that include of a rebuild-able file doesn't show a warning
# Savannah bug #102
run_make_test(q!
include foo
foo: ; @echo foo = bar > $@
run_make_test(q!
include inc1
all:;@echo $(FOO)
!,
'', "#MAKE#: 'foo' is up to date.\n");
rmfiles('foo');
}
'', "#MAKEFILE#:2: inc1: $ERR_unreadable_file\n#MAKE#: *** No rule to make target 'inc1'. Stop.", 512);
# Unreadable files that we know how to successfully recreate should work
run_make_test(sprintf(q!
all:;@echo $(FOO)
include inc1
inc1:; @%s $@ && echo FOO := bar > $@
!, $CMD_rmfile),
'', "bar");
rmfiles('inc1');
1;