[tz] tzcode error handling (patch 1 of 4)

Steve Summit scs at eskimo.com
Mon Dec 11 12:35:20 UTC 2017


This is Patch 1.  This patch improves localtime's error
handling, to optionally print actual error messages if a
requested zone can't be loaded.  For various reasons, though,
the error messages go only halfway: they will say things like
"can't load zone %s", but they are *not* able to say things
like "/usr/share/zoneinfo/America/New_York: No such file or
directory".  (Personally, I consider this sort of lack a
nearly fatal flaw in a system error message.)

As you might guess, this shortcoming will be addressed in Patch 2.

If it's not obvious, the way to enable the optional error
messages is either to call tz_set_stderr_warn_func(),
which requests that they be sent to stderr, or to call
tz_set_warn_func(), which lets you install your own
error-printing callback function (with the signature of printf).

Also enclosed is a one-line patch to tzcode's copy of date.c
adding a call to tz_set_stderr_warn_func.

One other mild drawback of this code is that it, unsurprisingly,
uses stdio.  Once this patch is applied, tzcode depends on stdio
again, not long after someone's careful attempt to break that
dependency.

This patch is with respect to 2017c.

					Steve Summit
					scs at eskimo.com
-------------- next part --------------
--- a/localtime.c	2017-11-30 20:31:30.000000000 -0500
+++ b/localtime.c	2017-12-06 19:24:38.000000000 -0500
@@ -10,6 +10,9 @@
 
 /*LINTLIBRARY*/
 
+#include <stdio.h>
+#include <stdarg.h>
+
 #define LOCALTIME_IMPLEMENTATION
 #include "private.h"
 
@@ -204,6 +207,8 @@
 # endif
 #endif
 
+static void (*wrnfunc)(char const *, ...) = NULL;
+
 /* Initialize *S to a value based on GMTOFF, ISDST, and ABBRIND.  */
 static void
 init_ttinfo(struct ttinfo *s, int_fast32_t gmtoff, bool isdst, int abbrind)
@@ -1060,8 +1065,11 @@
 	if (sizeof sp->chars < charcnt)
 	  return false;
 	load_ok = tzload(TZDEFRULES, sp, false) == 0;
-	if (!load_ok)
+	if (!load_ok) {
+		if(wrnfunc) (*wrnfunc)("can't load default rules %s",
+								TZDEFRULES);
 		sp->leapcnt = 0;		/* so, we're off a little */
+	}
 	if (*name != '\0') {
 		if (*name == '<') {
 			dstname = ++name;
@@ -1277,8 +1285,11 @@
 static void
 gmtload(struct state *const sp)
 {
-	if (tzload(gmt, sp, true) != 0)
-		tzparse(gmt, sp, true);
+	if (tzload(gmt, sp, true) != 0) {
+		if(!tzparse(gmt, sp, true)) {
+			if(wrnfunc) (*wrnfunc)("can't load GMT rules %s", gmt);
+		}
+	}
 }
 
 /* Initialize *SP to a value appropriate for the TZ setting NAME.
@@ -1305,6 +1316,9 @@
       err = 0;
     if (err == 0)
       scrub_abbrs(sp);
+    if(err) {
+      if(wrnfunc) (*wrnfunc)("can't load zone %s (using GMT)", name);
+    }
     return err;
   }
 }
@@ -2334,3 +2348,23 @@
 }
 
 #endif
+
+static void stderr_wrnfunc(char const *msg, ...)
+{
+	va_list argp;
+	va_start(argp, msg);
+	fprintf(stderr, "Warning: ");
+	vfprintf(stderr, msg, argp);
+	fprintf(stderr, "\n");
+	va_end(argp);
+}
+
+void tz_set_warn_func(void (*func)(char const *, ...))
+{
+	wrnfunc = func;
+}
+
+void tz_set_stderr_warn_func()
+{
+	wrnfunc = stderr_wrnfunc;
+}
-------------- next part --------------
--- a/private.h	2017-12-05 17:21:25.000000000 -0500
+++ b/private.h	2017-12-06 19:47:49.000000000 -0500
@@ -463,6 +463,8 @@
 time_t time(time_t *);
 void tzset(void);
 #endif
+void tz_set_warn_func(void (*)(char const *, ...));
+void tz_set_stderr_warn_func(void);
 
 #if !HAVE_DECL_ASCTIME_R && !defined asctime_r
 extern char *asctime_r(struct tm const *restrict, char *restrict);
-------------- next part --------------
--- a/date.c	2017-06-16 15:25:59.000000000 -0400
+++ b/date.c	2017-12-05 17:02:58.000000000 -0500
@@ -1,4 +1,4 @@
-/* Display or set the current time and date.  */
+/* Display the current time and date.  */
 
 /* Copyright 1985, 1987, 1988 The Regents of the University of California.
    All rights reserved.
@@ -76,6 +76,7 @@
 #endif /* defined(TEXTDOMAINDIR) */
 	textdomain(TZ_DOMAIN);
 #endif /* HAVE_GETTEXT */
+	tz_set_stderr_warn_func();
 	t = time(NULL);
 	format = NULL;
 	while ((ch = getopt(argc, argv, "ucr:")) != EOF && ch != -1) {


More information about the tz mailing list