Skip to content

Commit

Permalink
fixdep: use fflush() and ferror() to ensure successful write to files
Browse files Browse the repository at this point in the history
Currently, fixdep checks the return value from (v)printf(), but it does
not ensure the complete write to the .cmd file.

printf() just writes data to the internal buffer, which usually succeeds.
(Of course, it may fail for another reason, for example when the file
descriptor is closed, but that is another story.)

When the buffer (4k?) is full, an actual write occurs, and printf() may
really fail. One of typical cases is "No space left on device" when the
disk is full.

The data remaining in the buffer will be pushed out to the file when
the program exits, but we never know if it is successful.

One straight-forward fix would be to add the following code at the end
of the program.

   ret = fflush(stdout);
   if (ret < 0) {
          /* error handling */
   }

However, it is tedious to check the return code in all the call sites
of printf(), fflush(), fclose(), and whatever can cause actual writes
to the end device. Doing that lets the program bail out at the first
failure but is usually not worth the effort.

Instead, let's check the error status from ferror(). This is 'sticky',
so you need to check it just once. You still need to call fflush().

Signed-off-by: Masahiro Yamada <[email protected]>
Reviewed-by: David Laight <[email protected]>
Reviewed-by: Nick Desaulniers <[email protected]>
  • Loading branch information
masahir0y committed Mar 31, 2022
1 parent bbc90bc commit 6930437
Showing 1 changed file with 19 additions and 27 deletions.
46 changes: 19 additions & 27 deletions scripts/basic/fixdep.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,25 +105,6 @@ static void usage(void)
exit(1);
}

/*
* In the intended usage of this program, the stdout is redirected to .*.cmd
* files. The return value of printf() must be checked to catch any error,
* e.g. "No space left on device".
*/
static void xprintf(const char *format, ...)
{
va_list ap;
int ret;

va_start(ap, format);
ret = vprintf(format, ap);
if (ret < 0) {
perror("fixdep");
exit(1);
}
va_end(ap);
}

struct item {
struct item *next;
unsigned int len;
Expand Down Expand Up @@ -189,7 +170,7 @@ static void use_config(const char *m, int slen)

define_config(m, slen, hash);
/* Print out a dependency path from a symbol name. */
xprintf(" $(wildcard include/config/%.*s) \\\n", slen, m);
printf(" $(wildcard include/config/%.*s) \\\n", slen, m);
}

/* test if s ends in sub */
Expand Down Expand Up @@ -318,13 +299,13 @@ static void parse_dep_file(char *m, const char *target)
*/
if (!saw_any_target) {
saw_any_target = 1;
xprintf("source_%s := %s\n\n",
target, m);
xprintf("deps_%s := \\\n", target);
printf("source_%s := %s\n\n",
target, m);
printf("deps_%s := \\\n", target);
}
is_first_dep = 0;
} else {
xprintf(" %s \\\n", m);
printf(" %s \\\n", m);
}

buf = read_file(m);
Expand All @@ -347,8 +328,8 @@ static void parse_dep_file(char *m, const char *target)
exit(1);
}

xprintf("\n%s: $(deps_%s)\n\n", target, target);
xprintf("$(deps_%s):\n", target);
printf("\n%s: $(deps_%s)\n\n", target, target);
printf("$(deps_%s):\n", target);
}

int main(int argc, char *argv[])
Expand All @@ -363,11 +344,22 @@ int main(int argc, char *argv[])
target = argv[2];
cmdline = argv[3];

xprintf("cmd_%s := %s\n\n", target, cmdline);
printf("cmd_%s := %s\n\n", target, cmdline);

buf = read_file(depfile);
parse_dep_file(buf, target);
free(buf);

fflush(stdout);

/*
* In the intended usage, the stdout is redirected to .*.cmd files.
* Call ferror() to catch errors such as "No space left on device".
*/
if (ferror(stdout)) {
fprintf(stderr, "fixdep: not all data was written to the output\n");
exit(1);
}

return 0;
}

0 comments on commit 6930437

Please sign in to comment.