[tz] [PROPOSED PATCH 3/3] zic: check more consistently for I/O errors and improve diagnostics

Paul Eggert eggert at cs.ucla.edu
Tue Aug 19 06:27:26 UTC 2014


* zic.c (warnings): New static var.
(warning): Set it here.
(size_product, growalloc, main): Translate diagnostic.
(verror): Don't increment errors here.
(error): Set it here.
(close_file): New function.
(usage, dolink, infile, writezone): Use it.
(usage): Fit diagnostic in output lines better.
(main): Prefer 'return X;' to 'exit(X);'.
(main, infile, mkdirs): Use 'warning' for warnings.
Check for stderr output error.
(dolink, mkdirs): Don't assume gettext preserves errno.
---
 zic.c | 113 ++++++++++++++++++++++++++++++++----------------------------------
 1 file changed, 54 insertions(+), 59 deletions(-)

diff --git a/zic.c b/zic.c
index ea63f76..d230663 100644
--- a/zic.c
+++ b/zic.c
@@ -135,6 +135,7 @@ static int	yearistype(int year, const char * type);
 
 static int		charcnt;
 static int		errors;
+static int		warnings;
 static const char *	filename;
 static int		leapcnt;
 static int		leapseen;
@@ -364,7 +365,7 @@ static ATTRIBUTE_PURE size_t
 size_product(size_t nitems, size_t itemsize)
 {
 	if (SIZE_MAX / itemsize < nitems)
-		memory_exhausted("size overflow");
+		memory_exhausted(_("size overflow"));
 	return nitems * itemsize;
 }
 
@@ -389,7 +390,7 @@ growalloc(void *ptr, size_t itemsize, int nitems, int *nitems_alloc)
 	else {
 		int amax = INT_MAX < SIZE_MAX ? INT_MAX : SIZE_MAX;
 		if ((amax - 1) / 3 * 2 < *nitems_alloc)
-			memory_exhausted("int overflow");
+			memory_exhausted(_("int overflow"));
 		*nitems_alloc = *nitems_alloc + (*nitems_alloc >> 1) + 1;
 		return erealloc(ptr, size_product(*nitems_alloc, itemsize));
 	}
@@ -429,7 +430,6 @@ verror(const char *const string, va_list args)
 		fprintf(stderr, _(" (rule from \"%s\", line %d)"),
 			rfilename, rlinenum);
 	fprintf(stderr, "\n");
-	++errors;
 }
 
 static void ATTRIBUTE_FORMAT((printf, 1, 2))
@@ -439,6 +439,7 @@ error(const char *const string, ...)
 	va_start(args, string);
 	verror(string, args);
 	va_end(args);
+	errors = 1;
 }
 
 static void ATTRIBUTE_FORMAT((printf, 1, 2))
@@ -449,19 +450,35 @@ warning(const char *const string, ...)
 	va_start(args, string);
 	verror(string, args);
 	va_end(args);
-	--errors;
+	warnings = 1;
+}
+
+static void
+close_file(FILE *stream, char const *name)
+{
+  char const *e = (ferror(stream) ? _("I/O error")
+		   : fclose(stream) != 0 ? strerror(errno) : NULL);
+  if (e) {
+    fprintf(stderr, "%s: ", progname);
+    if (name)
+      fprintf(stderr, "%s: ", name);
+    fprintf(stderr, "%s\n", e);
+    exit(EXIT_FAILURE);
+  }
 }
 
 static _Noreturn void
 usage(FILE *stream, int status)
 {
-	fprintf(stream, _("%s: usage is %s \
-[ --version ] [ --help ] [ -v ] [ -l localtime ] [ -p posixrules ] \\\n\
-\t[ -d directory ] [ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\
-\n\
-Report bugs to %s.\n"),
-		       progname, progname, REPORT_BUGS_TO);
-	exit(status);
+  fprintf(stream,
+	  _("%s: usage is %s [ --version ] [ --help ] [ -v ] \\\n"
+	    "\t[ -l localtime ] [ -p posixrules ] [ -d directory ] \\\n"
+	    "\t[ -L leapseconds ] [ -y yearistype ] [ filename ... ]\n\n"
+	    "Report bugs to %s.\n"),
+	  progname, progname, REPORT_BUGS_TO);
+  if (status == EXIT_SUCCESS)
+    close_file(stream, NULL);
+  exit(status);
 }
 
 static const char *	psxrules;
@@ -491,12 +508,13 @@ main(int argc, char **argv)
 	if (TYPE_BIT(zic_t) < 64) {
 		fprintf(stderr, "%s: %s\n", progname,
 			_("wild compilation-time specification of zic_t"));
-		exit(EXIT_FAILURE);
+		return EXIT_FAILURE;
 	}
 	for (i = 1; i < argc; ++i)
 		if (strcmp(argv[i], "--version") == 0) {
 			printf("zic %s%s\n", PKGVERSION, TZVERSION);
-			exit(EXIT_SUCCESS);
+			close_file(stdout, NULL);
+			return EXIT_SUCCESS;
 		} else if (strcmp(argv[i], "--help") == 0) {
 			usage(stdout, EXIT_SUCCESS);
 		}
@@ -511,7 +529,7 @@ main(int argc, char **argv)
 					fprintf(stderr,
 _("%s: More than one -d option specified\n"),
 						progname);
-					exit(EXIT_FAILURE);
+					return EXIT_FAILURE;
 				}
 				break;
 			case 'l':
@@ -521,7 +539,7 @@ _("%s: More than one -d option specified\n"),
 					fprintf(stderr,
 _("%s: More than one -l option specified\n"),
 						progname);
-					exit(EXIT_FAILURE);
+					return EXIT_FAILURE;
 				}
 				break;
 			case 'p':
@@ -531,7 +549,7 @@ _("%s: More than one -l option specified\n"),
 					fprintf(stderr,
 _("%s: More than one -p option specified\n"),
 						progname);
-					exit(EXIT_FAILURE);
+					return EXIT_FAILURE;
 				}
 				break;
 			case 'y':
@@ -541,7 +559,7 @@ _("%s: More than one -p option specified\n"),
 					fprintf(stderr,
 _("%s: More than one -y option specified\n"),
 						progname);
-					exit(EXIT_FAILURE);
+					return EXIT_FAILURE;
 				}
 				break;
 			case 'L':
@@ -551,14 +569,14 @@ _("%s: More than one -y option specified\n"),
 					fprintf(stderr,
 _("%s: More than one -L option specified\n"),
 						progname);
-					exit(EXIT_FAILURE);
+					return EXIT_FAILURE;
 				}
 				break;
 			case 'v':
 				noise = TRUE;
 				break;
 			case 's':
-				printf("%s: -s ignored\n", progname);
+				warning(_("-s ignored\n"));
 				break;
 		}
 	if (optind == argc - 1 && strcmp(argv[optind], "=") == 0)
@@ -576,7 +594,7 @@ _("%s: More than one -L option specified\n"),
 	for (i = optind; i < argc; ++i)
 		infile(argv[i]);
 	if (errors)
-		exit(EXIT_FAILURE);
+		return EXIT_FAILURE;
 	associate();
 	for (i = 0; i < nzones; i = j) {
 		/*
@@ -599,14 +617,16 @@ _("%s: More than one -L option specified\n"),
 						warning(_("link to link"));
 	}
 	if (lcltime != NULL) {
-		eat("command line", 1);
+		eat(_("command line"), 1);
 		dolink(lcltime, TZDEFAULT);
 	}
 	if (psxrules != NULL) {
-		eat("command line", 1);
+		eat(_("command line"), 1);
 		dolink(psxrules, TZDEFRULES);
 	}
-	return (errors == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+	if (warnings && (ferror(stderr) || fclose(stderr) != 0))
+	  return EXIT_FAILURE;
+	return errors ? EXIT_FAILURE : EXIT_SUCCESS;
 }
 
 static void
@@ -695,9 +715,9 @@ dolink(const char *const fromfield, const char *const tofield)
 	*/
 	fromisdir = itsdir(fromname);
 	if (fromisdir) {
-		int err = fromisdir < 0 ? errno : EPERM;
+		char const *e = strerror(fromisdir < 0 ? errno : EPERM);
 		fprintf(stderr, _("%s: link from %s failed: %s"),
-			progname, fromname, strerror(err));
+			progname, fromname, e);
 		exit(EXIT_FAILURE);
 	}
 	if (itsdir(toname) <= 0)
@@ -753,18 +773,8 @@ warning(_("hard link failed, symbolic link used"));
 			}
 			while ((c = getc(fp)) != EOF)
 				putc(c, tp);
-			if (ferror(fp) || fclose(fp)) {
-				fprintf(stderr,
-					       _("%s: Error reading %s\n"),
-					       progname, fromname);
-				exit(EXIT_FAILURE);
-			}
-			if (ferror(tp) || fclose(tp)) {
-				fprintf(stderr,
-					       _("%s: Error writing %s\n"),
-					       progname, toname);
-				exit(EXIT_FAILURE);
-			}
+			close_file(fp, fromname);
+			close_file(tp, toname);
 			warning(_("link failed, copy used"));
 		}
 	}
@@ -981,7 +991,7 @@ infile(const char *name)
 					break;
 				case LC_LEAP:
 					if (name != leapsec)
-						fprintf(stderr,
+						warning(
 _("%s: Leap line in non leap seconds file %s\n"),
 							progname, name);
 					else	inleap(fields, nfields);
@@ -996,18 +1006,7 @@ _("%s: panic: Invalid l_value %d\n"),
 		}
 		free(fields);
 	}
-	if (ferror(fp)) {
-		fprintf(stderr, _("%s: Error reading %s\n"),
-			progname, filename);
-		exit(EXIT_FAILURE);
-	}
-	if (fp != stdin && fclose(fp)) {
-		const char *e = strerror(errno);
-
-		fprintf(stderr, _("%s: Error closing %s: %s\n"),
-			progname, filename, e);
-		exit(EXIT_FAILURE);
-	}
+	close_file(fp, filename);
 	if (wantcont)
 		error(_("expected continuation line not found"));
 }
@@ -1850,11 +1849,7 @@ writezone(const char *const name, const char *const string, char version)
 				putc(ttisgmts[i], fp);
 	}
 	fprintf(fp, "\n%s\n", string);
-	if (ferror(fp) || fclose(fp)) {
-		fprintf(stderr, _("%s: Error writing %s\n"),
-			progname, fullname);
-		exit(EXIT_FAILURE);
-	}
+	close_file(fp, fullname);
 	free(ats);
 }
 
@@ -2920,10 +2915,10 @@ mkdirs(char *argname)
 		if (mkdir(name, MKDIR_UMASK) != 0) {
 			int err = errno;
 			if (itsdir(name) <= 0) {
-				fprintf(stderr,
-					       _("%s: Can't create directory"
-						 " %s: %s\n"),
-					       progname, name, strerror(err));
+				char const *e = strerror(err);
+				warning(_("%s: Can't create directory"
+					  " %s: %s\n"),
+					progname, name, e);
 				free(name);
 				return -1;
 			}
-- 
1.9.1



More information about the tz mailing list