History

fixdep: use fflush() and ferror() to ensure successful write to files

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().

Masahiro Yamada committed 4 years ago

Commit 69304371 parent bbc90bc1 file · +19 −27Browse files

Showing the changes to scripts/basic (1 of 1 file). Show all

Unified · Split

scripts/basic/fixdep.c+19−27
@@ -105,25 +105,6 @@ static void usage(void) · 104 unmodified lines
105 exit(1);105 exit(1);
106}106}
107 107
108/*
109 * In the intended usage of this program, the stdout is redirected to .*.cmd
110 * files. The return value of printf() must be checked to catch any error,
111 * e.g. "No space left on device".
112 */
113static void xprintf(const char *format, ...)
114{
115 va_list ap;
116 int ret;
117
118 va_start(ap, format);
119 ret = vprintf(format, ap);
120 if (ret < 0) {
121 perror("fixdep");
122 exit(1);
123 }
124 va_end(ap);
125}
126
127struct item {108struct item {
128 struct item *next;109 struct item *next;
129 unsigned int len;110 unsigned int len;
@@ -189,7 +170,7 @@ static void use_config(const char *m, int slen) · 59 unmodified lines
189 170
190 define_config(m, slen, hash);171 define_config(m, slen, hash);
191 /* Print out a dependency path from a symbol name. */172 /* Print out a dependency path from a symbol name. */
192 xprintf(" $(wildcard include/config/%.*s) \\\n", slen, m);173 printf(" $(wildcard include/config/%.*s) \\\n", slen, m);
193}174}
194 175
195/* test if s ends in sub */176/* test if s ends in sub */
@@ -318,13 +299,13 @@ static void parse_dep_file(char *m, const char *target) · 122 unmodified lines
318 */299 */
319 if (!saw_any_target) {300 if (!saw_any_target) {
320 saw_any_target = 1;301 saw_any_target = 1;
321 xprintf("source_%s := %s\n\n",302 printf("source_%s := %s\n\n",
322 target, m);303 target, m);
323 xprintf("deps_%s := \\\n", target);304 printf("deps_%s := \\\n", target);
324 }305 }
325 is_first_dep = 0;306 is_first_dep = 0;
326 } else {307 } else {
327 xprintf(" %s \\\n", m);308 printf(" %s \\\n", m);
328 }309 }
329 310
330 buf = read_file(m);311 buf = read_file(m);
@@ -347,8 +328,8 @@ static void parse_dep_file(char *m, const char *target) · 16 unmodified lines
347 exit(1);328 exit(1);
348 }329 }
349 330
350 xprintf("\n%s: $(deps_%s)\n\n", target, target);331 printf("\n%s: $(deps_%s)\n\n", target, target);
351 xprintf("$(deps_%s):\n", target);332 printf("$(deps_%s):\n", target);
352}333}
353 334
354int main(int argc, char *argv[])335int main(int argc, char *argv[])
@@ -363,11 +344,22 @@ int main(int argc, char *argv[]) · 8 unmodified lines
363 target = argv[2];344 target = argv[2];
364 cmdline = argv[3];345 cmdline = argv[3];
365 346
366 xprintf("cmd_%s := %s\n\n", target, cmdline);347 printf("cmd_%s := %s\n\n", target, cmdline);
367 348
368 buf = read_file(depfile);349 buf = read_file(depfile);
369 parse_dep_file(buf, target);350 parse_dep_file(buf, target);
370 free(buf);351 free(buf);
371 352
353 fflush(stdout);
354
355 /*
356 * In the intended usage, the stdout is redirected to .*.cmd files.
357 * Call ferror() to catch errors such as "No space left on device".
358 */
359 if (ferror(stdout)) {
360 fprintf(stderr, "fixdep: not all data was written to the output\n");
361 exit(1);
362 }
363
372 return 0;364 return 0;
373}365}